Diff to HTML by rtfpessoa

Files changed (103) hide show
  1. src/bitcoin-tx.cpp +12 -26
  2. src/bitcoind.cpp +3 -3
  3. src/blockencodings.cpp +4 -1
  4. src/blockencodings.h +3 -1
  5. src/chain.cpp +14 -6
  6. src/chain.h +119 -10
  7. src/chainparams.cpp +159 -200
  8. src/chainparams.h +3 -3
  9. src/chainparamsbase.cpp +3 -3
  10. src/clientversion.cpp +7 -3
  11. src/clientversion.h +8 -1
  12. src/coins.cpp +4 -3
  13. src/coins.h +30 -5
  14. src/consensus/amount.h +12 -2
  15. src/consensus/params.h +10 -57
  16. src/consensus/tx_check.cpp +10 -0
  17. src/consensus/tx_verify.cpp +55 -14
  18. src/consensus/tx_verify.h +6 -1
  19. src/core_write.cpp +6 -3
  20. src/deploymentstatus.cpp +0 -34
  21. src/deploymentstatus.h +0 -55
  22. src/dummywallet.cpp +0 -2
  23. src/hash.cpp +9 -0
  24. src/hash.h +3 -0
  25. src/index/base.cpp +1 -1
  26. src/index/coinstatsindex.cpp +22 -22
  27. src/index/txindex.cpp +5 -0
  28. src/index/txindex.h +5 -0
  29. src/init.cpp +38 -126
  30. src/interfaces/chain.h +4 -30
  31. src/interfaces/init.h +4 -1
  32. src/interfaces/node.h +6 -6
  33. src/interfaces/wallet.h +9 -27
  34. src/kernel.cpp +725 -0
  35. src/kernel.h +71 -0
  36. src/kernelrecord.cpp +120 -0
  37. src/kernelrecord.h +60 -0
  38. src/net.cpp +5 -0
  39. src/net.h +16 -9
  40. src/net_processing.cpp +208 -76
  41. src/netmessagemaker.h +1 -1
  42. src/node/blockstorage.cpp +19 -197
  43. src/node/blockstorage.h +3 -50
  44. src/node/chainstate.cpp +1 -13
  45. src/node/chainstate.h +0 -2
  46. src/node/context.cpp +0 -1
  47. src/node/context.h +9 -8
  48. src/node/interfaces.cpp +13 -18
  49. src/node/miner.cpp +302 -49
  50. src/node/miner.h +15 -7
  51. src/node/psbt.cpp +3 -4
  52. src/node/psbt.h +0 -2
  53. src/node/transaction.cpp +1 -11
  54. src/node/transaction.h +1 -10
  55. src/node/ui_interface.cpp +1 -1
  56. src/node/ui_interface.h +3 -1
  57. src/policy/feerate.cpp +0 -45
  58. src/policy/feerate.h +0 -75
  59. src/policy/fees.cpp +0 -1017
  60. src/policy/fees.h +0 -310
  61. src/policy/policy.cpp +2 -48
  62. src/policy/policy.h +2 -18
  63. src/policy/rbf.cpp +0 -176
  64. src/policy/rbf.h +0 -102
  65. src/policy/settings.cpp +0 -3
  66. src/policy/settings.h +1 -4
  67. src/pow.cpp +42 -52
  68. src/pow.h +1 -2
  69. src/primitives/block.cpp +5 -3
  70. src/primitives/block.h +48 -2
  71. src/primitives/transaction.cpp +9 -6
  72. src/primitives/transaction.h +29 -3
  73. src/protocol.cpp +1 -0
  74. src/protocol.h +4 -1
  75. src/psbt.h +0 -1
  76. src/rest.cpp +0 -3
  77. src/script/interpreter.cpp +8 -0
  78. src/script/script.cpp +14 -0
  79. src/script/script.h +5 -1
  80. src/script/sign.cpp +4 -0
  81. src/script/standard.h +2 -2
  82. src/serialize.h +8 -4
  83. src/timedatadummy.cpp +7 -0
  84. src/txdb.cpp +17 -2
  85. src/txmempool.cpp +12 -71
  86. src/txmempool.h +3 -24
  87. src/uint256.h +5 -0
  88. src/undo.h +5 -2
  89. src/util.h +74 -0
  90. src/util/error.cpp +0 -2
  91. src/util/error.h +0 -1
  92. src/util/message.cpp +1 -1
  93. src/util/moneystr.cpp +1 -1
  94. src/util/strencodings.cpp +7 -3
  95. src/util/system.cpp +11 -10
  96. src/validation.cpp +472 -415
  97. src/validation.h +21 -17
  98. src/validationinterface.h +0 -1
  99. src/version.h +3 -2
  100. src/versionbits.cpp +0 -246
  101. src/versionbits.h +0 -107
  102. src/warnings.cpp +8 -0
  103. src/warnings.h +1 -0
src/bitcoin-tx.cpp CHANGED
@@ -14,14 +14,12 @@
14
14
  #include <key_io.h>
15
15
  #include <fs.h>
16
16
  #include <policy/policy.h>
17
- #include <policy/rbf.h>
18
17
  #include <primitives/transaction.h>
19
18
  #include <script/script.h>
20
19
  #include <script/sign.h>
21
20
  #include <script/signingprovider.h>
22
21
  #include <univalue.h>
23
22
  #include <util/moneystr.h>
24
- #include <util/rbf.h>
25
23
  #include <util/strencodings.h>
26
24
  #include <util/string.h>
27
25
  #include <util/system.h>
@@ -54,6 +52,7 @@ static void SetupBitcoinTxArgs(ArgsManager &argsman)
54
52
  argsman.AddArg("in=TXID:VOUT(:SEQUENCE_NUMBER)", "Add input to TX", ArgsManager::ALLOW_ANY, OptionsCategory::COMMANDS);
55
53
  argsman.AddArg("locktime=N", "Set TX lock time to N", ArgsManager::ALLOW_ANY, OptionsCategory::COMMANDS);
56
54
  argsman.AddArg("nversion=N", "Set TX version to N", ArgsManager::ALLOW_ANY, OptionsCategory::COMMANDS);
55
+ argsman.AddArg("ntime=N", "Set TX timestamp to N", ArgsManager::ALLOW_ANY, OptionsCategory::COMMANDS);
57
56
  argsman.AddArg("outaddr=VALUE:ADDRESS", "Add address-based output to TX", ArgsManager::ALLOW_ANY, OptionsCategory::COMMANDS);
58
57
  argsman.AddArg("outdata=[VALUE:]DATA", "Add data-based output to TX", ArgsManager::ALLOW_ANY, OptionsCategory::COMMANDS);
59
58
  argsman.AddArg("outmultisig=VALUE:REQUIRED:PUBKEYS:PUBKEY1:PUBKEY2:....[:FLAGS]", "Add Pay To n-of-m Multi-sig output to TX. n = REQUIRED, m = PUBKEYS. "
@@ -65,7 +64,6 @@ static void SetupBitcoinTxArgs(ArgsManager &argsman)
65
64
  argsman.AddArg("outscript=VALUE:SCRIPT[:FLAGS]", "Add raw script output to TX. "
66
65
  "Optionally add the \"W\" flag to produce a pay-to-witness-script-hash output. "
67
66
  "Optionally add the \"S\" flag to wrap the output in a pay-to-script-hash.", ArgsManager::ALLOW_ANY, OptionsCategory::COMMANDS);
68
- argsman.AddArg("replaceable(=N)", "Set RBF opt-in sequence number for input N (if not provided, opt-in all available inputs)", ArgsManager::ALLOW_ANY, OptionsCategory::COMMANDS);
69
67
  argsman.AddArg("sign=SIGHASH-FLAGS", "Add zero or more signatures to transaction. "
70
68
  "This command requires JSON registers:"
71
69
  "prevtxs=JSON object, "
@@ -101,14 +99,14 @@ static int AppInitRawTx(int argc, char* argv[])
101
99
 
102
100
  if (argc < 2 || HelpRequested(gArgs) || gArgs.IsArgSet("-version")) {
103
101
  // First part of help message is specific to this utility
104
- std::string strUsage = PACKAGE_NAME " bitcoin-tx utility version " + FormatFullVersion() + "\n";
102
+ std::string strUsage = PACKAGE_NAME " peercoin-tx utility version " + FormatFullVersion() + "\n";
105
103
 
106
104
  if (gArgs.IsArgSet("-version")) {
107
105
  strUsage += FormatParagraph(LicenseInfo());
108
106
  } else {
109
107
  strUsage += "\n"
110
- "Usage: bitcoin-tx [options] <hex-tx> [commands] Update hex-encoded bitcoin transaction\n"
111
- "or: bitcoin-tx [options] -create [commands] Create hex-encoded bitcoin transaction\n"
108
+ "Usage: peercoin-tx [options] <hex-tx> [commands] Update hex-encoded peercoin transaction\n"
109
+ "or: peercoin-tx [options] -create [commands] Create hex-encoded peercoin transaction\n"
112
110
  "\n";
113
111
  strUsage += gArgs.GetHelpMessage();
114
112
  }
@@ -219,24 +217,13 @@ static void MutateTxLocktime(CMutableTransaction& tx, const std::string& cmdVal)
219
217
  tx.nLockTime = (unsigned int) newLocktime;
220
218
  }
221
219
 
222
- static void MutateTxRBFOptIn(CMutableTransaction& tx, const std::string& strInIdx)
220
+ static void MutateTxTime(CMutableTransaction& tx, const std::string& cmdVal)
223
221
  {
224
- // parse requested index
225
- int64_t inIdx;
226
- if (!ParseInt64(strInIdx, &inIdx) || inIdx < 0 || inIdx >= static_cast<int64_t>(tx.vin.size())) {
227
- throw std::runtime_error("Invalid TX input index '" + strInIdx + "'");
228
- }
222
+ int64_t newTime;
223
+ if (!ParseInt64(cmdVal, &newTime) || newTime < 0LL || newTime > 0xffffffffLL)
224
+ throw std::runtime_error("Invalid TX time requested: '" + cmdVal + "'");
229
225
 
230
- // set the nSequence to MAX_INT - 2 (= RBF opt in flag)
231
- int cnt = 0;
232
- for (CTxIn& txin : tx.vin) {
233
- if (strInIdx == "" || cnt == inIdx) {
234
- if (txin.nSequence > MAX_BIP125_RBF_SEQUENCE) {
235
- txin.nSequence = MAX_BIP125_RBF_SEQUENCE;
236
- }
237
- }
238
- ++cnt;
239
- }
226
+ tx.nTime = (unsigned int) newTime;
240
227
  }
241
228
 
242
229
  template <typename T>
@@ -559,7 +546,7 @@ static CAmount AmountFromValue(const UniValue& value)
559
546
  if (!value.isNum() && !value.isStr())
560
547
  throw std::runtime_error("Amount is not a number or string");
561
548
  CAmount amount;
562
- if (!ParseFixedPoint(value.getValStr(), 8, &amount))
549
+ if (!ParseFixedPoint(value.getValStr(), 6, &amount))
563
550
  throw std::runtime_error("Invalid amount");
564
551
  if (!MoneyRange(amount))
565
552
  throw std::runtime_error("Amount out of range");
@@ -708,9 +695,8 @@ static void MutateTx(CMutableTransaction& tx, const std::string& command,
708
695
  MutateTxVersion(tx, commandVal);
709
696
  else if (command == "locktime")
710
697
  MutateTxLocktime(tx, commandVal);
711
- else if (command == "replaceable") {
712
- MutateTxRBFOptIn(tx, commandVal);
713
- }
698
+ else if (command == "ntime")
699
+ MutateTxTime(tx, commandVal);
714
700
 
715
701
  else if (command == "delin")
716
702
  MutateTxDelInput(tx, commandVal);
src/bitcoind.cpp CHANGED
@@ -114,7 +114,7 @@ static bool AppInit(NodeContext& node, int argc, char* argv[])
114
114
 
115
115
  util::ThreadSetInternalName("init");
116
116
 
117
- // If Qt is used, parameters/bitcoin.conf are parsed in qt/bitcoin.cpp's main()
117
+ // If Qt is used, parameters/peercoin.conf are parsed in qt/bitcoin.cpp's main()
118
118
  ArgsManager& args = *Assert(node.args);
119
119
  SetupServerArgs(args);
120
120
  std::string error;
@@ -129,7 +129,7 @@ static bool AppInit(NodeContext& node, int argc, char* argv[])
129
129
  if (args.IsArgSet("-version")) {
130
130
  strUsage += FormatParagraph(LicenseInfo());
131
131
  } else {
132
- strUsage += "\nUsage: bitcoind [options] Start " PACKAGE_NAME "\n"
132
+ strUsage += "\nUsage: peercoind [options] Start " PACKAGE_NAME "\n"
133
133
  "\n";
134
134
  strUsage += args.GetHelpMessage();
135
135
  }
@@ -165,7 +165,7 @@ static bool AppInit(NodeContext& node, int argc, char* argv[])
165
165
  // Error out when loose non-argument tokens are encountered on command line
166
166
  for (int i = 1; i < argc; i++) {
167
167
  if (!IsSwitchChar(argv[i][0])) {
168
- return InitError(Untranslated(strprintf("Command line contains unexpected token '%s', see bitcoind -h for a list of options.\n", argv[i])));
168
+ return InitError(Untranslated(strprintf("Command line contains unexpected token '%s', see peercoind -h for a list of options.\n", argv[i])));
169
169
  }
170
170
  }
171
171
 
src/blockencodings.cpp CHANGED
@@ -18,10 +18,11 @@
18
18
 
19
19
  CBlockHeaderAndShortTxIDs::CBlockHeaderAndShortTxIDs(const CBlock& block, bool fUseWTXID) :
20
20
  nonce(GetRand(std::numeric_limits<uint64_t>::max())),
21
- shorttxids(block.vtx.size() - 1), prefilledtxn(1), header(block) {
21
+ shorttxids(block.vtx.size() - 1), prefilledtxn(1), header(block), vchBlockSig(block.vchBlockSig) {
22
22
  FillShortTxIDSelector();
23
23
  //TODO: Use our mempool prior to block acceptance to predictively fill more than just the coinbase
24
24
  prefilledtxn[0] = {0, block.vtx[0]};
25
+ header.nFlags = block.nFlags;
25
26
  for (size_t i = 1; i < block.vtx.size(); i++) {
26
27
  const CTransaction& tx = *block.vtx[i];
27
28
  shorttxids[i - 1] = GetShortID(fUseWTXID ? tx.GetWitnessHash() : tx.GetHash());
@@ -54,6 +55,7 @@ ReadStatus PartiallyDownloadedBlock::InitData(const CBlockHeaderAndShortTxIDs& c
54
55
 
55
56
  assert(header.IsNull() && txn_available.empty());
56
57
  header = cmpctblock.header;
58
+ vchBlockSig = cmpctblock.vchBlockSig;
57
59
  txn_available.resize(cmpctblock.BlockTxCount());
58
60
 
59
61
  int32_t lastprefilledindex = -1;
@@ -177,6 +179,7 @@ ReadStatus PartiallyDownloadedBlock::FillBlock(CBlock& block, const std::vector<
177
179
  assert(!header.IsNull());
178
180
  uint256 hash = header.GetHash();
179
181
  block = header;
182
+ block.vchBlockSig = vchBlockSig;
180
183
  block.vtx.resize(txn_available.size());
181
184
 
182
185
  size_t tx_missing_offset = 0;
src/blockencodings.h CHANGED
@@ -100,6 +100,7 @@ public:
100
100
  static constexpr int SHORTTXIDS_LENGTH = 6;
101
101
 
102
102
  CBlockHeader header;
103
+ std::vector<unsigned char> vchBlockSig;
103
104
 
104
105
  // Dummy for deserialization
105
106
  CBlockHeaderAndShortTxIDs() {}
@@ -112,7 +113,7 @@ public:
112
113
 
113
114
  SERIALIZE_METHODS(CBlockHeaderAndShortTxIDs, obj)
114
115
  {
115
- READWRITE(obj.header, obj.nonce, Using<VectorFormatter<CustomUintFormatter<SHORTTXIDS_LENGTH>>>(obj.shorttxids), obj.prefilledtxn);
116
+ READWRITE(obj.header, obj.nonce, obj.vchBlockSig, Using<VectorFormatter<CustomUintFormatter<SHORTTXIDS_LENGTH>>>(obj.shorttxids), obj.prefilledtxn);
116
117
  if (ser_action.ForRead()) {
117
118
  if (obj.BlockTxCount() > std::numeric_limits<uint16_t>::max()) {
118
119
  throw std::ios_base::failure("indexes overflowed 16 bits");
@@ -129,6 +130,7 @@ protected:
129
130
  const CTxMemPool* pool;
130
131
  public:
131
132
  CBlockHeader header;
133
+ std::vector<unsigned char> vchBlockSig;
132
134
  explicit PartiallyDownloadedBlock(CTxMemPool* poolIn) : pool(poolIn) {}
133
135
 
134
136
  // extra_txn is a list of extra transactions to look at, in <witness hash, reference> form
src/chain.cpp CHANGED
@@ -122,7 +122,7 @@ void CBlockIndex::BuildSkip()
122
122
  pskip = pprev->GetAncestor(GetSkipHeight(nHeight));
123
123
  }
124
124
 
125
- arith_uint256 GetBlockProof(const CBlockIndex& block)
125
+ arith_uint256 GetBlockTrust(const CBlockIndex& block)
126
126
  {
127
127
  arith_uint256 bnTarget;
128
128
  bool fNegative;
@@ -134,20 +134,20 @@ arith_uint256 GetBlockProof(const CBlockIndex& block)
134
134
  // as it's too large for an arith_uint256. However, as 2**256 is at least as large
135
135
  // as bnTarget+1, it is equal to ((2**256 - bnTarget - 1) / (bnTarget+1)) + 1,
136
136
  // or ~bnTarget / (bnTarget+1) + 1.
137
- return (~bnTarget / (bnTarget + 1)) + 1;
137
+ return block.IsProofOfStake() ? (~bnTarget / (bnTarget + 1)) + 1 : 1;
138
138
  }
139
139
 
140
140
  int64_t GetBlockProofEquivalentTime(const CBlockIndex& to, const CBlockIndex& from, const CBlockIndex& tip, const Consensus::Params& params)
141
141
  {
142
142
  arith_uint256 r;
143
143
  int sign = 1;
144
- if (to.nChainWork > from.nChainWork) {
145
- r = to.nChainWork - from.nChainWork;
144
+ if (to.nChainTrust > from.nChainTrust) {
145
+ r = to.nChainTrust - from.nChainTrust;
146
146
  } else {
147
- r = from.nChainWork - to.nChainWork;
147
+ r = from.nChainTrust - to.nChainTrust;
148
148
  sign = -1;
149
149
  }
150
- r = r * arith_uint256(params.nPowTargetSpacing) / GetBlockProof(tip);
150
+ r = r * arith_uint256(params.nPowTargetSpacing) / GetBlockTrust(tip);
151
151
  if (r.bits() > 63) {
152
152
  return sign * std::numeric_limits<int64_t>::max();
153
153
  }
@@ -172,3 +172,11 @@ const CBlockIndex* LastCommonAncestor(const CBlockIndex* pa, const CBlockIndex*
172
172
  assert(pa == pb);
173
173
  return pa;
174
174
  }
175
+
176
+ // peercoin: find last block index up to pindex
177
+ const CBlockIndex* GetLastBlockIndex(const CBlockIndex* pindex, bool fProofOfStake)
178
+ {
179
+ while (pindex && pindex->pprev && (pindex->IsProofOfStake() != fProofOfStake))
180
+ pindex = pindex->pprev;
181
+ return pindex;
182
+ }
src/chain.h CHANGED
@@ -14,13 +14,16 @@
14
14
  #include <tinyformat.h>
15
15
  #include <uint256.h>
16
16
 
17
+ #include <util/moneystr.h>
18
+
17
19
  #include <vector>
18
20
 
19
21
  /**
20
22
  * Maximum amount of time that a block timestamp is allowed to exceed the
21
23
  * current network-adjusted time before the block will be accepted.
22
24
  */
23
- static constexpr int64_t MAX_FUTURE_BLOCK_TIME = 2 * 60 * 60;
25
+ static constexpr int64_t MAX_FUTURE_BLOCK_TIME_PREV9 = 2 * 60 * 60;
26
+ static constexpr int64_t MAX_FUTURE_BLOCK_TIME = 15 * 60;
24
27
 
25
28
  /**
26
29
  * Timestamp window used as a grace period by code that compares external
@@ -28,7 +31,7 @@ static constexpr int64_t MAX_FUTURE_BLOCK_TIME = 2 * 60 * 60;
28
31
  * to block timestamps. This should be set at least as high as
29
32
  * MAX_FUTURE_BLOCK_TIME.
30
33
  */
31
- static constexpr int64_t TIMESTAMP_WINDOW = MAX_FUTURE_BLOCK_TIME;
34
+ static constexpr int64_t TIMESTAMP_WINDOW = MAX_FUTURE_BLOCK_TIME_PREV9;
32
35
 
33
36
  /**
34
37
  * Maximum gap between node time and block time used
@@ -173,7 +176,7 @@ public:
173
176
  unsigned int nUndoPos GUARDED_BY(::cs_main){0};
174
177
 
175
178
  //! (memory only) Total amount of work (expected number of hashes) in the chain up to and including this block
176
- arith_uint256 nChainWork{};
179
+ arith_uint256 nChainTrust{};
177
180
 
178
181
  //! Number of transactions in this block.
179
182
  //! Note: in a potential headers-first mode, this number cannot be relied upon
@@ -213,6 +216,66 @@ public:
213
216
  //! (memory only) Maximum nTime in the chain up to and including this block.
214
217
  unsigned int nTimeMax{0};
215
218
 
219
+ // peercoin
220
+ // peercoin: money supply related block index fields
221
+ int64_t nMint{0};
222
+ int64_t nMoneySupply{0};
223
+
224
+ // peercoin: proof-of-stake related block index fields
225
+ unsigned int nFlags{0}; // peercoin: block index flags
226
+ enum
227
+ {
228
+ BLOCK_PROOF_OF_STAKE = (1 << 0), // is proof-of-stake block
229
+ BLOCK_STAKE_ENTROPY = (1 << 1), // entropy bit for stake modifier
230
+ BLOCK_STAKE_MODIFIER = (1 << 2), // regenerated stake modifier
231
+ };
232
+ uint64_t nStakeModifier{0}; // hash modifier for proof-of-stake
233
+ unsigned int nStakeModifierChecksum{0}; // checksum of index; in-memeory only
234
+ COutPoint prevoutStake{};
235
+ unsigned int nStakeTime{0};
236
+ uint256 hashProofOfStake{};
237
+
238
+ bool IsProofOfWork() const
239
+ {
240
+ return !(nFlags & BLOCK_PROOF_OF_STAKE);
241
+ }
242
+
243
+ bool IsProofOfStake() const
244
+ {
245
+ return (nFlags & BLOCK_PROOF_OF_STAKE);
246
+ }
247
+
248
+ void SetProofOfStake()
249
+ {
250
+ nFlags |= BLOCK_PROOF_OF_STAKE;
251
+ }
252
+
253
+ unsigned int GetStakeEntropyBit() const
254
+ {
255
+ return ((nFlags & BLOCK_STAKE_ENTROPY) >> 1);
256
+ }
257
+
258
+ bool SetStakeEntropyBit(unsigned int nEntropyBit)
259
+ {
260
+ if (nEntropyBit > 1)
261
+ return false;
262
+ nFlags |= (nEntropyBit? BLOCK_STAKE_ENTROPY : 0);
263
+ return true;
264
+ }
265
+
266
+ bool GeneratedStakeModifier() const
267
+ {
268
+ return (nFlags & BLOCK_STAKE_MODIFIER);
269
+ }
270
+
271
+ void SetStakeModifier(uint64_t nModifier, bool fGeneratedStakeModifier)
272
+ {
273
+ nStakeModifier = nModifier;
274
+ if (fGeneratedStakeModifier)
275
+ nFlags |= BLOCK_STAKE_MODIFIER;
276
+ }
277
+ // peercoin end
278
+
216
279
  CBlockIndex()
217
280
  {
218
281
  }
@@ -222,7 +285,8 @@ public:
222
285
  hashMerkleRoot{block.hashMerkleRoot},
223
286
  nTime{block.nTime},
224
287
  nBits{block.nBits},
225
- nNonce{block.nNonce}
288
+ nNonce{block.nNonce},
289
+ nFlags{block.nFlags}
226
290
  {
227
291
  }
228
292
 
@@ -258,6 +322,7 @@ public:
258
322
  block.nTime = nTime;
259
323
  block.nBits = nBits;
260
324
  block.nNonce = nNonce;
325
+ block.nFlags = nFlags;
261
326
  return block;
262
327
  }
263
328
 
@@ -271,7 +336,7 @@ public:
271
336
  * downloaded (and stored to disk) at some point.
272
337
  *
273
338
  * Does not imply the transactions are consensus-valid (ConnectTip might fail)
274
- * Does not imply the transactions are still stored on disk. (IsBlockPruned might return true)
339
+ * Does not imply the transactions are still stored on disk.
275
340
  */
276
341
  bool HaveTxsDownloaded() const { return nChainTx != 0; }
277
342
 
@@ -285,6 +350,32 @@ public:
285
350
  return (int64_t)nTimeMax;
286
351
  }
287
352
 
353
+ /**
354
+ * Duplicate from bitcoinrpc that originaly define this method.
355
+ * May require some cleanup since this method should be available both for rpc
356
+ * and qt clients.
357
+ */
358
+ double GetBlockDifficulty() const
359
+ {
360
+ int nShift = (nBits >> 24) & 0xff;
361
+
362
+ double dDiff =
363
+ (double)0x0000ffff / (double)(nBits & 0x00ffffff);
364
+
365
+ while (nShift < 29)
366
+ {
367
+ dDiff *= 256.0;
368
+ nShift++;
369
+ }
370
+ while (nShift > 29)
371
+ {
372
+ dDiff /= 256.0;
373
+ nShift--;
374
+ }
375
+
376
+ return dDiff;
377
+ }
378
+
288
379
  static constexpr int nMedianTimeSpan = 11;
289
380
 
290
381
  int64_t GetMedianTimePast() const
@@ -303,10 +394,15 @@ public:
303
394
 
304
395
  std::string ToString() const
305
396
  {
306
- return strprintf("CBlockIndex(pprev=%p, nHeight=%d, merkle=%s, hashBlock=%s)",
307
- pprev, nHeight,
308
- hashMerkleRoot.ToString(),
309
- GetBlockHash().ToString());
397
+ return strprintf("CBlockIndex(nprev=%08x, nFile=%d, nHeight=%d, nMint=%s, nMoneySupply=%s, nFlags=(%s)(%d)(%s), nStakeModifier=%016llx, nStakeModifierChecksum=%08x, hashProofOfStake=%s, prevoutStake=(%s), nStakeTime=%d merkle=%s, hashBlock=%s)",
398
+ pprev, nFile, nHeight,
399
+ FormatMoney(nMint), FormatMoney(nMoneySupply),
400
+ GeneratedStakeModifier() ? "MOD" : "-", GetStakeEntropyBit(), IsProofOfStake()? "PoS" : "PoW",
401
+ nStakeModifier, nStakeModifierChecksum,
402
+ hashProofOfStake.ToString(),
403
+ prevoutStake.ToString(), nStakeTime,
404
+ hashMerkleRoot.ToString().substr(0,10),
405
+ GetBlockHash().ToString().substr(0,20));
310
406
  }
311
407
 
312
408
  //! Check whether this block index entry is valid up to the passed validity level.
@@ -357,7 +453,7 @@ public:
357
453
  const CBlockIndex* GetAncestor(int height) const;
358
454
  };
359
455
 
360
- arith_uint256 GetBlockProof(const CBlockIndex& block);
456
+ arith_uint256 GetBlockTrust(const CBlockIndex& block);
361
457
  /** Return the time it would take to redo the work difference between from and to, assuming the current hashrate corresponds to the difficulty at tip, in seconds. */
362
458
  int64_t GetBlockProofEquivalentTime(const CBlockIndex& to, const CBlockIndex& from, const CBlockIndex& tip, const Consensus::Params&);
363
459
  /** Find the forking point between two chain tips. */
@@ -393,6 +489,17 @@ public:
393
489
  if (obj.nStatus & BLOCK_HAVE_DATA) READWRITE(VARINT(obj.nDataPos));
394
490
  if (obj.nStatus & BLOCK_HAVE_UNDO) READWRITE(VARINT(obj.nUndoPos));
395
491
 
492
+ READWRITE(obj.nMint);
493
+ READWRITE(obj.nMoneySupply);
494
+ READWRITE(obj.nFlags);
495
+ READWRITE(obj.nStakeModifier);
496
+ if (obj.nFlags & BLOCK_PROOF_OF_STAKE)
497
+ {
498
+ READWRITE(obj.prevoutStake);
499
+ READWRITE(obj.nStakeTime);
500
+ READWRITE(obj.hashProofOfStake);
501
+ }
502
+
396
503
  // block header
397
504
  READWRITE(obj.nVersion);
398
505
  READWRITE(obj.hashPrev);
@@ -491,4 +598,6 @@ public:
491
598
  CBlockIndex* FindEarliestAtLeast(int64_t nTime, int height) const;
492
599
  };
493
600
 
601
+ const CBlockIndex* GetLastBlockIndex(const CBlockIndex* pindex, bool fProofOfStake);
602
+
494
603
  #endif // BITCOIN_CHAIN_H
src/chainparams.cpp CHANGED
@@ -16,18 +16,19 @@
16
16
  #include <boost/algorithm/string/classification.hpp>
17
17
  #include <boost/algorithm/string/split.hpp>
18
18
 
19
- static CBlock CreateGenesisBlock(const char* pszTimestamp, const CScript& genesisOutputScript, uint32_t nTime, uint32_t nNonce, uint32_t nBits, int32_t nVersion, const CAmount& genesisReward)
19
+ static CBlock CreateGenesisBlock(const char* pszTimestamp, const CScript& genesisOutputScript, uint32_t nTimeTx, uint32_t nTimeBlock, uint32_t nNonce, uint32_t nBits, int32_t nVersion, const CAmount& genesisReward)
20
20
  {
21
21
  CMutableTransaction txNew;
22
22
  txNew.nVersion = 1;
23
23
  txNew.vin.resize(1);
24
24
  txNew.vout.resize(1);
25
- txNew.vin[0].scriptSig = CScript() << 486604799 << CScriptNum(4) << std::vector<unsigned char>((const unsigned char*)pszTimestamp, (const unsigned char*)pszTimestamp + strlen(pszTimestamp));
25
+ txNew.vin[0].scriptSig = CScript() << 486604799 << CScriptNum(9999) << std::vector<unsigned char>((const unsigned char*)pszTimestamp, (const unsigned char*)pszTimestamp + strlen(pszTimestamp));
26
26
  txNew.vout[0].nValue = genesisReward;
27
27
  txNew.vout[0].scriptPubKey = genesisOutputScript;
28
+ txNew.nTime = nTimeTx;
28
29
 
29
30
  CBlock genesis;
30
- genesis.nTime = nTime;
31
+ genesis.nTime = nTimeBlock;
31
32
  genesis.nBits = nBits;
32
33
  genesis.nNonce = nNonce;
33
34
  genesis.nVersion = nVersion;
@@ -48,11 +49,11 @@ static CBlock CreateGenesisBlock(const char* pszTimestamp, const CScript& genesi
48
49
  * CTxOut(nValue=50.00000000, scriptPubKey=0x5F1DF16B2B704C8A578D0B)
49
50
  * vMerkleTree: 4a5e1e
50
51
  */
51
- static CBlock CreateGenesisBlock(uint32_t nTime, uint32_t nNonce, uint32_t nBits, int32_t nVersion, const CAmount& genesisReward)
52
+ static CBlock CreateGenesisBlock(uint32_t nTimeTx, uint32_t nTimeBlock, uint32_t nNonce, uint32_t nBits, int32_t nVersion, const CAmount& genesisReward)
52
53
  {
53
- const char* pszTimestamp = "The Times 03/Jan/2009 Chancellor on brink of second bailout for banks";
54
- const CScript genesisOutputScript = CScript() << ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5f") << OP_CHECKSIG;
55
- return CreateGenesisBlock(pszTimestamp, genesisOutputScript, nTime, nNonce, nBits, nVersion, genesisReward);
54
+ const char* pszTimestamp = "Matonis 07-AUG-2012 Parallel Currencies And The Roadmap To Monetary Freedom";
55
+ const CScript genesisOutputScript = CScript();
56
+ return CreateGenesisBlock(pszTimestamp, genesisOutputScript, nTimeTx, nTimeBlock, nNonce, nBits, nVersion, genesisReward);
56
57
  }
57
58
 
58
59
  /**
@@ -64,80 +65,71 @@ public:
64
65
  strNetworkID = CBaseChainParams::MAIN;
65
66
  consensus.signet_blocks = false;
66
67
  consensus.signet_challenge.clear();
67
- consensus.nSubsidyHalvingInterval = 210000;
68
- consensus.BIP16Exception = uint256S("0x00000000000002dc756eebf4f49723ed8d30cc28a5f108eb94b1ba88ac4f9c22");
69
- consensus.BIP34Height = 227931;
70
- consensus.BIP34Hash = uint256S("0x000000000000024b89b42a942fe0d9fea3bb44ab7bd1b19115dd6a759c0808b8");
71
- consensus.BIP65Height = 388381; // 000000000000000004c2b624ed5d7756c508d90fd0da2c7c679febfa6c4735f0
72
- consensus.BIP66Height = 363725; // 00000000000000000379eaa19dce8c9b722d46ae6a57c2f1a988119488b50931
73
- consensus.CSVHeight = 419328; // 000000000000000004a1b34462cb8aeebd5799177f7a29cf28f2d1961716b5b5
74
- consensus.SegwitHeight = 481824; // 0000000000000000001c8018d9cb3b742ef25114f27563e3fc4a1902167f9893
75
- consensus.MinBIP9WarningHeight = 483840; // segwit activation height + miner confirmation window
76
- consensus.powLimit = uint256S("00000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffff");
77
- consensus.nPowTargetTimespan = 14 * 24 * 60 * 60; // two weeks
78
- consensus.nPowTargetSpacing = 10 * 60;
68
+ //consensus.BIP16Height = 0;
69
+ consensus.BIP34Height = 339994;
70
+ consensus.BIP34Hash = uint256S("000000000000000237f50af4cfe8924e8693abc5bd8ae5abb95bc6d230f5953f");
71
+ consensus.powLimit = uint256S("00000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); // ~arith_uint256(0) >> 32;
72
+ consensus.bnInitialHashTarget = uint256S("0000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff"); // ~arith_uint256(0) >> 40;
73
+
74
+ consensus.nTargetTimespan = 7 * 24 * 60 * 60; // one week
75
+ consensus.nStakeTargetSpacing = 10 * 60; // 10-minute block spacing
76
+ consensus.nTargetSpacingWorkMax = 12 * consensus.nStakeTargetSpacing; // 2-hour
77
+ consensus.nPowTargetSpacing = consensus.nStakeTargetSpacing;
78
+ consensus.nStakeMinAge = 60 * 60 * 24 * 30; // minimum age for coin age
79
+ consensus.nStakeMaxAge = 60 * 60 * 24 * 90;
80
+ consensus.nModifierInterval = 6 * 60 * 60; // Modifier interval: time to elapse before new modifier is computed
81
+ consensus.nCoinbaseMaturity = 500;
82
+
79
83
  consensus.fPowAllowMinDifficultyBlocks = false;
80
84
  consensus.fPowNoRetargeting = false;
81
85
  consensus.nRuleChangeActivationThreshold = 1815; // 90% of 2016
82
86
  consensus.nMinerConfirmationWindow = 2016; // nPowTargetTimespan / nPowTargetSpacing
83
- consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].bit = 28;
84
- consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nStartTime = Consensus::BIP9Deployment::NEVER_ACTIVE;
85
- consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nTimeout = Consensus::BIP9Deployment::NO_TIMEOUT;
86
- consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].min_activation_height = 0; // No activation delay
87
87
 
88
- // Deployment of Taproot (BIPs 340-342)
89
- consensus.vDeployments[Consensus::DEPLOYMENT_TAPROOT].bit = 2;
90
- consensus.vDeployments[Consensus::DEPLOYMENT_TAPROOT].nStartTime = 1619222400; // April 24th, 2021
91
- consensus.vDeployments[Consensus::DEPLOYMENT_TAPROOT].nTimeout = 1628640000; // August 11th, 2021
92
- consensus.vDeployments[Consensus::DEPLOYMENT_TAPROOT].min_activation_height = 709632; // Approximately November 12th, 2021
88
+ consensus.SegwitHeight = 455470;
93
89
 
94
- consensus.nMinimumChainWork = uint256S("0x00000000000000000000000000000000000000002927cdceccbd5209e81e80db");
95
- consensus.defaultAssumeValid = uint256S("0x000000000000000000052d314a259755ca65944e68df6b12a067ea8f1f5a7091"); // 724466
90
+ consensus.nMinimumChainWork = uint256S("0x000000000000000000000000000000000000000000000000002a0fac8b39f476"); // 350000
91
+ consensus.defaultAssumeValid = uint256S("0xa3a0ffa0dbca75923ad6a53d3878d62f8b35c363282df3f13ded9e4fda921e63"); // 380000
96
92
 
97
93
  /**
98
94
  * The message start string is designed to be unlikely to occur in normal data.
99
95
  * The characters are rarely used upper ASCII, not valid as UTF-8, and produce
100
96
  * a large 32-bit integer with any alignment.
101
97
  */
102
- pchMessageStart[0] = 0xf9;
103
- pchMessageStart[1] = 0xbe;
104
- pchMessageStart[2] = 0xb4;
105
- pchMessageStart[3] = 0xd9;
106
- nDefaultPort = 8333;
98
+ pchMessageStart[0] = 0xe6;
99
+ pchMessageStart[1] = 0xe8;
100
+ pchMessageStart[2] = 0xe9;
101
+ pchMessageStart[3] = 0xe5;
102
+ nDefaultPort = 9901;
107
103
  nPruneAfterHeight = 100000;
108
- m_assumed_blockchain_size = 460;
109
- m_assumed_chain_state_size = 6;
104
+ m_assumed_blockchain_size = 1;
110
105
 
111
- genesis = CreateGenesisBlock(1231006505, 2083236893, 0x1d00ffff, 1, 50 * COIN);
106
+ genesis = CreateGenesisBlock(1345083810, 1345084287, 2179302059u, 0x1d00ffff, 1, 0);
112
107
  consensus.hashGenesisBlock = genesis.GetHash();
113
- assert(consensus.hashGenesisBlock == uint256S("0x000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f"));
114
- assert(genesis.hashMerkleRoot == uint256S("0x4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b"));
108
+ assert(consensus.hashGenesisBlock == uint256S("0x0000000032fe677166d54963b62a4677d8957e87c508eaa4fd7eb1c880cd27e3"));
109
+ assert(genesis.hashMerkleRoot == uint256S("0x3c2d8f85fab4d17aac558cc648a1a58acff0de6deb890c29985690052c5993c2"));
115
110
 
116
111
  // Note that of those which support the service bits prefix, most only support a subset of
117
112
  // possible options.
118
113
  // This is fine at runtime as we'll fall back to using them as an addrfetch if they don't support the
119
114
  // service bits we want, but we should get them updated to support all service bits wanted by any
120
115
  // release ASAP to avoid it where possible.
121
- vSeeds.emplace_back("seed.bitcoin.sipa.be."); // Pieter Wuille, only supports x1, x5, x9, and xd
122
- vSeeds.emplace_back("dnsseed.bluematt.me."); // Matt Corallo, only supports x9
123
- vSeeds.emplace_back("dnsseed.bitcoin.dashjr.org."); // Luke Dashjr
124
- vSeeds.emplace_back("seed.bitcoinstats.com."); // Christian Decker, supports x1 - xf
125
- vSeeds.emplace_back("seed.bitcoin.jonasschnelli.ch."); // Jonas Schnelli, only supports x1, x5, x9, and xd
126
- vSeeds.emplace_back("seed.btc.petertodd.org."); // Peter Todd, only supports x1, x5, x9, and xd
127
- vSeeds.emplace_back("seed.bitcoin.sprovoost.nl."); // Sjors Provoost
128
- vSeeds.emplace_back("dnsseed.emzy.de."); // Stephan Oeste
129
- vSeeds.emplace_back("seed.bitcoin.wiz.biz."); // Jason Maurice
130
-
131
- base58Prefixes[PUBKEY_ADDRESS] = std::vector<unsigned char>(1,0);
132
- base58Prefixes[SCRIPT_ADDRESS] = std::vector<unsigned char>(1,5);
133
- base58Prefixes[SECRET_KEY] = std::vector<unsigned char>(1,128);
116
+ vSeeds.emplace_back("seed.peercoin.net");
117
+ vSeeds.emplace_back("seed2.peercoin.net");
118
+ vSeeds.emplace_back("seed.peercoin-library.org");
119
+ vSeeds.emplace_back("seed.ppcoin.info");
120
+
121
+ base58Prefixes[PUBKEY_ADDRESS] = std::vector<unsigned char>(1,55); // peercoin: addresses begin with 'P'
122
+ base58Prefixes[SCRIPT_ADDRESS] = std::vector<unsigned char>(1,117); // peercoin: addresses begin with 'p'
123
+ base58Prefixes[SECRET_KEY] = std::vector<unsigned char>(1,183);
134
124
  base58Prefixes[EXT_PUBLIC_KEY] = {0x04, 0x88, 0xB2, 0x1E};
135
125
  base58Prefixes[EXT_SECRET_KEY] = {0x04, 0x88, 0xAD, 0xE4};
136
126
 
137
- bech32_hrp = "bc";
127
+ // human readable prefix to bench32 address
128
+ bech32_hrp = "pc";
138
129
 
139
130
  vFixedSeeds = std::vector<uint8_t>(std::begin(chainparams_seed_main), std::end(chainparams_seed_main));
140
131
 
132
+ fMiningRequiresPeers = true;
141
133
  fDefaultConsistencyChecks = false;
142
134
  fRequireStandard = true;
143
135
  m_is_test_chain = false;
@@ -145,19 +137,19 @@ public:
145
137
 
146
138
  checkpointData = {
147
139
  {
148
- { 11111, uint256S("0x0000000069e244f73d78e8fd29ba2fd2ed618bd6fa2ee92559f542fdb26e7c1d")},
149
- { 33333, uint256S("0x000000002dd5588a74784eaa7ab0507a18ad16a236e7b1ce69f00d7ddfb5d0a6")},
150
- { 74000, uint256S("0x0000000000573993a3c9e41ce34471c079dcf5f52a0e824a81e7f953b8661a20")},
151
- {105000, uint256S("0x00000000000291ce28027faea320c8d2b054b2e0fe44a773f3eefb151d6bdc97")},
152
- {134444, uint256S("0x00000000000005b12ffd4cd315cd34ffd4a594f430ac814c91184a0d42d2b0fe")},
153
- {168000, uint256S("0x000000000000099e61ea72015e79632f216fe6cb33d7899acb35b75c8303b763")},
154
- {193000, uint256S("0x000000000000059f452a5f7340de6682a977387c17010ff6e6c3bd83ca8b1317")},
155
- {210000, uint256S("0x000000000000048b95347e83192f69cf0366076336c639f9b7228e9ba171342e")},
156
- {216116, uint256S("0x00000000000001b4f4b433e81ee46494af945cf96014816a4e2370f11b23df4e")},
157
- {225430, uint256S("0x00000000000001c108384350f74090433e7fcf79a606b8e797f065b130575932")},
158
- {250000, uint256S("0x000000000000003887df1f29024b06fc2200b55f8af8f35453d7be294df2d214")},
159
- {279000, uint256S("0x0000000000000001ae8c72a0b0c301f67e3afca10e819efa9041e458e9bd7e40")},
160
- {295000, uint256S("0x00000000000000004d9b4ef50f0f9d686fd69db2e03af35a100370c64632a983")},
140
+ { 0, uint256S("0x0000000032fe677166d54963b62a4677d8957e87c508eaa4fd7eb1c880cd27e3")},
141
+ { 19080, uint256S("0x000000000000bca54d9ac17881f94193fd6a270c1bb21c3bf0b37f588a40dbd7")},
142
+ { 30583, uint256S("0xd39d1481a7eecba48932ea5913be58ad3894c7ee6d5a8ba8abeb772c66a6696e")},
143
+ { 99999, uint256S("0x27fd5e1de16a4270eb8c68dee2754a64da6312c7c3a0e99a7e6776246be1ee3f")},
144
+ {219999, uint256S("0xab0dad4b10d2370f009ed6df6effca1ba42f01d5070d6b30afeedf6463fbe7a2")},
145
+ {336000, uint256S("0x4d261cef6e61a5ed8325e560f1d6e36f4698853a4c7134677f47a1d1d842bdf6")},
146
+ {371850, uint256S("0x6b18adcb0a6e080dae85b74eee2b83fabb157bbea64fab0ed2192b2f6d5b89f3")},
147
+ {407813, uint256S("0x00000000000000012730b0f48bed8afbeb08164c9d63597afb082e82ea05cec9")},
148
+ {443561, uint256S("0xf81cea8e4e40b2cfcc13a8bd82436399c35a55df951b95e7128601c1838029ed")},
149
+ {455470, uint256S("0xd1472c26229f90b8589d331aa47ba9023cb953b92dce342c753e7a6b3431bf1e")},
150
+ {479189, uint256S("0xc9c065028b20a23fbb9627bbca5946c7497f11e1f72433d4d215c79047cf06f2")},
151
+ {504051, uint256S("0xff65454ebdf1d89174bec10a3c016db92f7b1d9a4759603472842f254be8d7b3")},
152
+ {589659, uint256S("0x967c14abf21214639aeff0a270c4543cd3b80fe53178384ac5aa3c277662f1d0")},
161
153
  }
162
154
  };
163
155
 
@@ -166,10 +158,12 @@ public:
166
158
  };
167
159
 
168
160
  chainTxData = ChainTxData{
169
- // Data from RPC: getchaintxstats 4096 000000000000000000052d314a259755ca65944e68df6b12a067ea8f1f5a7091
170
- /* nTime */ 1645542140,
171
- /* nTxCount */ 712531200,
172
- /* dTxRate */ 2.891036496010309,
161
+ // Data as of block 967c14abf21214639aeff0a270c4543cd3b80fe53178384ac5aa3c277662f1d0 (height 589659).
162
+ 1635782211, // * UNIX timestamp of last known number of transactions
163
+ 1992832, // * total number of transactions between genesis and that timestamp
164
+ // (the tx=... number in the ChainStateFlushed debug.log lines)
165
+ 0.006862798 // * estimated number of transactions per second after that timestamp
166
+ // 1992832/(1635782211-1345400356) = 0.006862798
173
167
  };
174
168
  }
175
169
  };
@@ -183,57 +177,51 @@ public:
183
177
  strNetworkID = CBaseChainParams::TESTNET;
184
178
  consensus.signet_blocks = false;
185
179
  consensus.signet_challenge.clear();
186
- consensus.nSubsidyHalvingInterval = 210000;
187
- consensus.BIP16Exception = uint256S("0x00000000dd30457c001f4095d208cc1296b0eed002427aa599874af7a432b105");
188
- consensus.BIP34Height = 21111;
189
- consensus.BIP34Hash = uint256S("0x0000000023b3a96d3484e5abb3755c413e7d41500f8e2a5c3f0dd01299cd8ef8");
190
- consensus.BIP65Height = 581885; // 00000000007f6655f22f98e72ed80d8b06dc761d5da09df0fa1dc4be4f861eb6
191
- consensus.BIP66Height = 330776; // 000000002104c8c45e99a8853285a3b592602a3ccde2b832481da85e9e4ba182
192
- consensus.CSVHeight = 770112; // 00000000025e930139bac5c6c31a403776da130831ab85be56578f3fa75369bb
193
- consensus.SegwitHeight = 834624; // 00000000002b980fcd729daaa248fd9316a5200e9b367f4ff2c42453e84201ca
194
- consensus.MinBIP9WarningHeight = 836640; // segwit activation height + miner confirmation window
195
- consensus.powLimit = uint256S("00000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffff");
196
- consensus.nPowTargetTimespan = 14 * 24 * 60 * 60; // two weeks
197
- consensus.nPowTargetSpacing = 10 * 60;
180
+ //consensus.BIP16Height = 0;
181
+ consensus.BIP34Height = 293368;
182
+ consensus.BIP34Hash = uint256S("00000002c0b976c7a5c9878f1cec63fb4d88d68d614aedeaf8158c42d904795e");
183
+ consensus.powLimit = uint256S("0000000fffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); // ~arith_uint256(0) >> 28;
184
+ consensus.bnInitialHashTarget = uint256S("00000007ffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); // ~arith_uint256(0) >> 29;
185
+
186
+ consensus.nTargetTimespan = 7 * 24 * 60 * 60; // one week
187
+ consensus.nStakeTargetSpacing = 10 * 60; // 10-minute block spacing
188
+ consensus.nTargetSpacingWorkMax = 12 * consensus.nStakeTargetSpacing; // 2-hour
189
+ consensus.nPowTargetSpacing = consensus.nStakeTargetSpacing;
190
+ consensus.nStakeMinAge = 60 * 60 * 24; // test net min age is 1 day
191
+ consensus.nStakeMaxAge = 60 * 60 * 24 * 90;
192
+ consensus.nModifierInterval = 60 * 20; // Modifier interval: time to elapse before new modifier is computed
193
+ consensus.nCoinbaseMaturity = 60;
194
+
198
195
  consensus.fPowAllowMinDifficultyBlocks = true;
199
196
  consensus.fPowNoRetargeting = false;
200
197
  consensus.nRuleChangeActivationThreshold = 1512; // 75% for testchains
201
198
  consensus.nMinerConfirmationWindow = 2016; // nPowTargetTimespan / nPowTargetSpacing
202
- consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].bit = 28;
203
- consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nStartTime = Consensus::BIP9Deployment::NEVER_ACTIVE;
204
- consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nTimeout = Consensus::BIP9Deployment::NO_TIMEOUT;
205
- consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].min_activation_height = 0; // No activation delay
206
199
 
207
- // Deployment of Taproot (BIPs 340-342)
208
- consensus.vDeployments[Consensus::DEPLOYMENT_TAPROOT].bit = 2;
209
- consensus.vDeployments[Consensus::DEPLOYMENT_TAPROOT].nStartTime = 1619222400; // April 24th, 2021
210
- consensus.vDeployments[Consensus::DEPLOYMENT_TAPROOT].nTimeout = 1628640000; // August 11th, 2021
211
- consensus.vDeployments[Consensus::DEPLOYMENT_TAPROOT].min_activation_height = 0; // No activation delay
200
+ consensus.SegwitHeight = 394215;
212
201
 
213
- consensus.nMinimumChainWork = uint256S("0x00000000000000000000000000000000000000000000064728c7be6fe4b2f961");
214
- consensus.defaultAssumeValid = uint256S("0x00000000000163cfb1f97c4e4098a3692c8053ad9cab5ad9c86b338b5c00b8b7"); // 2143398
202
+ consensus.nMinimumChainWork = uint256S("0x00");
203
+ consensus.defaultAssumeValid = uint256S("0x0000000002e9e7b00e1f6dc5123a04aad68dd0f0968d8c7aa45f6640795c37b1"); //1135275
215
204
 
216
- pchMessageStart[0] = 0x0b;
217
- pchMessageStart[1] = 0x11;
218
- pchMessageStart[2] = 0x09;
219
- pchMessageStart[3] = 0x07;
220
- nDefaultPort = 18333;
205
+ pchMessageStart[0] = 0xcb;
206
+ pchMessageStart[1] = 0xf2;
207
+ pchMessageStart[2] = 0xc0;
208
+ pchMessageStart[3] = 0xef;
209
+ nDefaultPort = 9903;
221
210
  nPruneAfterHeight = 1000;
222
- m_assumed_blockchain_size = 40;
223
- m_assumed_chain_state_size = 2;
211
+ m_assumed_blockchain_size = 2;
224
212
 
225
- genesis = CreateGenesisBlock(1296688602, 414098458, 0x1d00ffff, 1, 50 * COIN);
213
+ genesis = CreateGenesisBlock(1345083810, 1345090000, 122894938, 0x1d0fffff, 1, 0);
226
214
  consensus.hashGenesisBlock = genesis.GetHash();
227
- assert(consensus.hashGenesisBlock == uint256S("0x000000000933ea01ad0ee984209779baaec3ced90fa3f408719526f8d77f4943"));
228
- assert(genesis.hashMerkleRoot == uint256S("0x4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b"));
215
+ assert(consensus.hashGenesisBlock == uint256S("0x00000001f757bb737f6596503e17cd17b0658ce630cc727c0cca81aec47c9f06"));
216
+ assert(genesis.hashMerkleRoot == uint256S("0x3c2d8f85fab4d17aac558cc648a1a58acff0de6deb890c29985690052c5993c2"));
229
217
 
230
218
  vFixedSeeds.clear();
231
219
  vSeeds.clear();
232
220
  // nodes with support for servicebits filtering should be at the top
233
- vSeeds.emplace_back("testnet-seed.bitcoin.jonasschnelli.ch.");
234
- vSeeds.emplace_back("seed.tbtc.petertodd.org.");
235
- vSeeds.emplace_back("seed.testnet.bitcoin.sprovoost.nl.");
236
- vSeeds.emplace_back("testnet-seed.bluematt.me."); // Just a static list of stable node(s), only supports x9
221
+ vSeeds.emplace_back("tseed.peercoin.net");
222
+ vSeeds.emplace_back("tseed2.peercoin.net");
223
+ vSeeds.emplace_back("tseed.peercoin-library.org");
224
+ vSeeds.emplace_back("testseed.ppcoin.info");
237
225
 
238
226
  base58Prefixes[PUBKEY_ADDRESS] = std::vector<unsigned char>(1,111);
239
227
  base58Prefixes[SCRIPT_ADDRESS] = std::vector<unsigned char>(1,196);
@@ -241,10 +229,12 @@ public:
241
229
  base58Prefixes[EXT_PUBLIC_KEY] = {0x04, 0x35, 0x87, 0xCF};
242
230
  base58Prefixes[EXT_SECRET_KEY] = {0x04, 0x35, 0x83, 0x94};
243
231
 
244
- bech32_hrp = "tb";
232
+ // human readable prefix to bench32 address
233
+ bech32_hrp = "tpc";
245
234
 
246
235
  vFixedSeeds = std::vector<uint8_t>(std::begin(chainparams_seed_test), std::end(chainparams_seed_test));
247
236
 
237
+ fMiningRequiresPeers = true;
248
238
  fDefaultConsistencyChecks = false;
249
239
  fRequireStandard = false;
250
240
  m_is_test_chain = true;
@@ -252,7 +242,18 @@ public:
252
242
 
253
243
  checkpointData = {
254
244
  {
255
- {546, uint256S("000000002a936ca763904c3c35fce2f3556c559c0214345d31b1bcebf76acb70")},
245
+ { 0, uint256S("0x00000001f757bb737f6596503e17cd17b0658ce630cc727c0cca81aec47c9f06")},
246
+ { 19080, uint256S("0xb054d63d41852d71b611eaa8eca37d9fddca69b5013cf0966d453402ec8005ce")},
247
+ { 30583, uint256S("0x5179c0c496b5d25ab81ffe14273ea6928c6ff81c0a0d6a83b5d7d41d64886300")},
248
+ { 99999, uint256S("0xa7b03b14b8673683d972ab81775f3e85fea4fe689874b5956183466535dc651c")},
249
+ {219999, uint256S("0x0691bb86c92762c5c4c5a3723585ebeb7ec59310bbb0bdb6666551ab24ad919e")},
250
+ {336000, uint256S("0xf07adf61615c529f7c282b858d13d3e037b197324cb12e0669c461947494c4e3")},
251
+ {372751, uint256S("0x000000000000148db599b217c117b5104f5043c55f6ca2a8a065d9fab9f9bba1")},
252
+ {382019, uint256S("0x3ab75769d7957d9bf0857b5019d0a0e41044fa9ecf30b2f9c32aa457b0864ce5")},
253
+ {408500, uint256S("0x1636ac08b073d26b28fa40243d58dd5deb215752efe094c92c61998e4e9baf3f")},
254
+ {412691, uint256S("0x0e20318be88f07f521453435b37cfc516c3de07264a78ed7170985a1126126ab")},
255
+ {441299, uint256S("0x4091d0836a37c50ceee876000ac0cb251fd10031dab901d2c0677cd86283096e")},
256
+ {442735, uint256S("0x1b83b33894d51be0b8b323bfab093f638915236e0e40ba3b52bb33fdbc4053cd")},
256
257
  }
257
258
  };
258
259
 
@@ -261,10 +262,14 @@ public:
261
262
  };
262
263
 
263
264
  chainTxData = ChainTxData{
264
- // Data from RPC: getchaintxstats 4096 00000000d18cfe81cbeea665076807789bd8f831d557632e635bc6e3c003069e
265
- /* nTime */ 1645635119,
266
- /* nTxCount */ 62226341,
267
- /* dTxRate */ 0.07717997442177152,
265
+ // Data as of block 0x1b83b33894d51be0b8b323bfab093f638915236e0e40ba3b52bb33fdbc4053cd (height 442735)
266
+ 1632053274, // * UNIX timestamp of last known number of transactions
267
+ 863997, // * total number of transactions between genesis and that timestamp
268
+
269
+ // (the tx=... number in the SetBestChain debug.log lines)
270
+ 0.003020718 // * estimated number of transactions per second after that timestamp
271
+ // 863997/(1632053274-1346029522) = 0.003020718
272
+
268
273
  };
269
274
  }
270
275
  };
@@ -289,7 +294,6 @@ public:
289
294
  consensus.nMinimumChainWork = uint256S("0x000000000000000000000000000000000000000000000000000000de26b0e471");
290
295
  consensus.defaultAssumeValid = uint256S("0x00000112852484b5fe3451572368f93cfd2723279af3464e478aee35115256ef"); // 78788
291
296
  m_assumed_blockchain_size = 1;
292
- m_assumed_chain_state_size = 0;
293
297
  chainTxData = ChainTxData{
294
298
  // Data from RPC: getchaintxstats 4096 0000003d9144c56ac110ae04a0c271a0acce2f14f426b39fdf0d938c96d2eb09
295
299
  /* nTime */ 1645631279,
@@ -306,7 +310,6 @@ public:
306
310
  consensus.nMinimumChainWork = uint256{};
307
311
  consensus.defaultAssumeValid = uint256{};
308
312
  m_assumed_blockchain_size = 0;
309
- m_assumed_chain_state_size = 0;
310
313
  chainTxData = ChainTxData{
311
314
  0,
312
315
  0,
@@ -322,15 +325,12 @@ public:
322
325
  strNetworkID = CBaseChainParams::SIGNET;
323
326
  consensus.signet_blocks = true;
324
327
  consensus.signet_challenge.assign(bin.begin(), bin.end());
325
- consensus.nSubsidyHalvingInterval = 210000;
326
328
  consensus.BIP16Exception = uint256{};
327
329
  consensus.BIP34Height = 1;
328
330
  consensus.BIP34Hash = uint256{};
329
- consensus.BIP65Height = 1;
330
- consensus.BIP66Height = 1;
331
331
  consensus.CSVHeight = 1;
332
332
  consensus.SegwitHeight = 1;
333
- consensus.nPowTargetTimespan = 14 * 24 * 60 * 60; // two weeks
333
+ // consensus.nPowTargetTimespan = 14 * 24 * 60 * 60; // two weeks
334
334
  consensus.nPowTargetSpacing = 10 * 60;
335
335
  consensus.fPowAllowMinDifficultyBlocks = false;
336
336
  consensus.fPowNoRetargeting = false;
@@ -338,6 +338,7 @@ public:
338
338
  consensus.nMinerConfirmationWindow = 2016; // nPowTargetTimespan / nPowTargetSpacing
339
339
  consensus.MinBIP9WarningHeight = 0;
340
340
  consensus.powLimit = uint256S("00000377ae000000000000000000000000000000000000000000000000000000");
341
+ /*
341
342
  consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].bit = 28;
342
343
  consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nStartTime = Consensus::BIP9Deployment::NEVER_ACTIVE;
343
344
  consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nTimeout = Consensus::BIP9Deployment::NO_TIMEOUT;
@@ -348,7 +349,7 @@ public:
348
349
  consensus.vDeployments[Consensus::DEPLOYMENT_TAPROOT].nStartTime = Consensus::BIP9Deployment::ALWAYS_ACTIVE;
349
350
  consensus.vDeployments[Consensus::DEPLOYMENT_TAPROOT].nTimeout = Consensus::BIP9Deployment::NO_TIMEOUT;
350
351
  consensus.vDeployments[Consensus::DEPLOYMENT_TAPROOT].min_activation_height = 0; // No activation delay
351
-
352
+ */
352
353
  // message start is defined as the first 4 bytes of the sha256d of the block script
353
354
  CHashWriter h(SER_DISK, 0);
354
355
  h << consensus.signet_challenge;
@@ -358,10 +359,10 @@ public:
358
359
  nDefaultPort = 38333;
359
360
  nPruneAfterHeight = 1000;
360
361
 
361
- genesis = CreateGenesisBlock(1598918400, 52613770, 0x1e0377ae, 1, 50 * COIN);
362
+ genesis = CreateGenesisBlock(1345083810, 1345090000, 122894938, 0x1d0fffff, 1, 0);
362
363
  consensus.hashGenesisBlock = genesis.GetHash();
363
- assert(consensus.hashGenesisBlock == uint256S("0x00000008819873e925422c1ff0f99f7cc9bbb232af63a077a480a3633bee1ef6"));
364
- assert(genesis.hashMerkleRoot == uint256S("0x4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b"));
364
+ assert(consensus.hashGenesisBlock == uint256S("0x00000001f757bb737f6596503e17cd17b0658ce630cc727c0cca81aec47c9f06"));
365
+ assert(genesis.hashMerkleRoot == uint256S("0x3c2d8f85fab4d17aac558cc648a1a58acff0de6deb890c29985690052c5993c2"));
365
366
 
366
367
  vFixedSeeds.clear();
367
368
 
@@ -384,70 +385,67 @@ public:
384
385
  * Regression test: intended for private networks only. Has minimal difficulty to ensure that
385
386
  * blocks can be found instantly.
386
387
  */
388
+
387
389
  class CRegTestParams : public CChainParams {
388
390
  public:
389
391
  explicit CRegTestParams(const ArgsManager& args) {
390
392
  strNetworkID = CBaseChainParams::REGTEST;
391
393
  consensus.signet_blocks = false;
392
394
  consensus.signet_challenge.clear();
393
- consensus.nSubsidyHalvingInterval = 150;
394
395
  consensus.BIP16Exception = uint256();
395
396
  consensus.BIP34Height = 1; // Always active unless overridden
396
397
  consensus.BIP34Hash = uint256();
397
- consensus.BIP65Height = 1; // Always active unless overridden
398
- consensus.BIP66Height = 1; // Always active unless overridden
399
- consensus.CSVHeight = 1; // Always active unless overridden
400
- consensus.SegwitHeight = 0; // Always active unless overridden
401
- consensus.MinBIP9WarningHeight = 0;
402
- consensus.powLimit = uint256S("7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff");
403
- consensus.nPowTargetTimespan = 14 * 24 * 60 * 60; // two weeks
404
- consensus.nPowTargetSpacing = 10 * 60;
398
+ consensus.powLimit = uint256S("7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); // ~arith_uint256(0) >> 28;
399
+ consensus.bnInitialHashTarget = uint256S("7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); // ~arith_uint256(0) >> 29;
400
+
401
+ consensus.nTargetTimespan = 7 * 24 * 60 * 60; // two weeks
402
+ consensus.nStakeTargetSpacing = 10 * 60; // 10-minute block spacing
403
+ consensus.nTargetSpacingWorkMax = 12 * consensus.nStakeTargetSpacing; // 2-hour
404
+ consensus.nPowTargetSpacing = consensus.nStakeTargetSpacing;
405
+
406
+ consensus.nStakeMinAge = 60 * 60 * 24; // test net min age is 1 day
407
+ consensus.nStakeMaxAge = 60 * 60 * 24 * 90;
408
+ consensus.nModifierInterval = 60 * 20; // Modifier interval: time to elapse before new modifier is computed
409
+ consensus.nCoinbaseMaturity = 60;
410
+
405
411
  consensus.fPowAllowMinDifficultyBlocks = true;
406
412
  consensus.fPowNoRetargeting = true;
407
413
  consensus.nRuleChangeActivationThreshold = 108; // 75% for testchains
408
414
  consensus.nMinerConfirmationWindow = 144; // Faster than normal for regtest (144 instead of 2016)
409
-
410
- consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].bit = 28;
411
- consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nStartTime = 0;
412
- consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nTimeout = Consensus::BIP9Deployment::NO_TIMEOUT;
415
+ /*
413
416
  consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].min_activation_height = 0; // No activation delay
414
417
 
415
418
  consensus.vDeployments[Consensus::DEPLOYMENT_TAPROOT].bit = 2;
416
419
  consensus.vDeployments[Consensus::DEPLOYMENT_TAPROOT].nStartTime = Consensus::BIP9Deployment::ALWAYS_ACTIVE;
417
420
  consensus.vDeployments[Consensus::DEPLOYMENT_TAPROOT].nTimeout = Consensus::BIP9Deployment::NO_TIMEOUT;
418
421
  consensus.vDeployments[Consensus::DEPLOYMENT_TAPROOT].min_activation_height = 0; // No activation delay
419
-
422
+ */
420
423
  consensus.nMinimumChainWork = uint256{};
421
424
  consensus.defaultAssumeValid = uint256{};
422
425
 
423
- pchMessageStart[0] = 0xfa;
424
- pchMessageStart[1] = 0xbf;
425
- pchMessageStart[2] = 0xb5;
426
- pchMessageStart[3] = 0xda;
427
- nDefaultPort = 18444;
428
- nPruneAfterHeight = args.GetBoolArg("-fastprune", false) ? 100 : 1000;
426
+ pchMessageStart[0] = 0xcb;
427
+ pchMessageStart[1] = 0xf2;
428
+ pchMessageStart[2] = 0xc0;
429
+ pchMessageStart[3] = 0xef;
430
+ nDefaultPort = 9903;
431
+ nPruneAfterHeight = 1000;
429
432
  m_assumed_blockchain_size = 0;
430
- m_assumed_chain_state_size = 0;
431
433
 
432
- UpdateActivationParametersFromArgs(args);
434
+ genesis = CreateGenesisBlock(1345083810, 1345090000, 122894938, 0x1d0fffff, 1, 0);
433
435
 
434
- genesis = CreateGenesisBlock(1296688602, 2, 0x207fffff, 1, 50 * COIN);
435
436
  consensus.hashGenesisBlock = genesis.GetHash();
436
- assert(consensus.hashGenesisBlock == uint256S("0x0f9188f13cb7b2c71f2a335e3a4fc328bf5beb436012afca590b1a11466e2206"));
437
- assert(genesis.hashMerkleRoot == uint256S("0x4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b"));
437
+ assert(consensus.hashGenesisBlock == uint256S("0x00000001f757bb737f6596503e17cd17b0658ce630cc727c0cca81aec47c9f06"));
438
+ assert(genesis.hashMerkleRoot == uint256S("0x3c2d8f85fab4d17aac558cc648a1a58acff0de6deb890c29985690052c5993c2"));
438
439
 
439
440
  vFixedSeeds.clear(); //!< Regtest mode doesn't have any fixed seeds.
440
441
  vSeeds.clear();
441
442
  vSeeds.emplace_back("dummySeed.invalid.");
442
443
 
443
- fDefaultConsistencyChecks = true;
444
- fRequireStandard = true;
445
444
  m_is_test_chain = true;
446
445
  m_is_mockable_chain = true;
447
-
448
446
  checkpointData = {
449
447
  {
450
- {0, uint256S("0f9188f13cb7b2c71f2a335e3a4fc328bf5beb436012afca590b1a11466e2206")},
448
+ {0, uint256S("0x00000001f757bb737f6596503e17cd17b0658ce630cc727c0cca81aec47c9f06")},
451
449
  }
452
450
  };
453
451
 
@@ -474,17 +472,11 @@ public:
474
472
  base58Prefixes[EXT_PUBLIC_KEY] = {0x04, 0x35, 0x87, 0xCF};
475
473
  base58Prefixes[EXT_SECRET_KEY] = {0x04, 0x35, 0x83, 0x94};
476
474
 
477
- bech32_hrp = "bcrt";
478
- }
479
-
480
- /**
481
- * Allows modifying the Version Bits regtest parameters.
482
- */
483
- void UpdateVersionBitsParameters(Consensus::DeploymentPos d, int64_t nStartTime, int64_t nTimeout, int min_activation_height)
484
- {
485
- consensus.vDeployments[d].nStartTime = nStartTime;
486
- consensus.vDeployments[d].nTimeout = nTimeout;
487
- consensus.vDeployments[d].min_activation_height = min_activation_height;
475
+ bech32_hrp = "pcrt";
476
+ fMiningRequiresPeers = false;
477
+ fDefaultConsistencyChecks = true;
478
+ fRequireStandard = false;
479
+ //fMineBlocksOnDemand = true;
488
480
  }
489
481
  void UpdateActivationParametersFromArgs(const ArgsManager& args);
490
482
  };
@@ -507,9 +499,9 @@ static void MaybeUpdateHeights(const ArgsManager& args, Consensus::Params& conse
507
499
  } else if (name == "bip34") {
508
500
  consensus.BIP34Height = int{height};
509
501
  } else if (name == "dersig") {
510
- consensus.BIP66Height = int{height};
502
+ //consensus.BIP66Height = int{height};
511
503
  } else if (name == "cltv") {
512
- consensus.BIP65Height = int{height};
504
+ //consensus.BIP65Height = int{height};
513
505
  } else if (name == "csv") {
514
506
  consensus.CSVHeight = int{height};
515
507
  } else {
@@ -521,40 +513,7 @@ static void MaybeUpdateHeights(const ArgsManager& args, Consensus::Params& conse
521
513
  void CRegTestParams::UpdateActivationParametersFromArgs(const ArgsManager& args)
522
514
  {
523
515
  MaybeUpdateHeights(args, consensus);
524
-
525
- if (!args.IsArgSet("-vbparams")) return;
526
-
527
- for (const std::string& strDeployment : args.GetArgs("-vbparams")) {
528
- std::vector<std::string> vDeploymentParams;
529
- boost::split(vDeploymentParams, strDeployment, boost::is_any_of(":"));
530
- if (vDeploymentParams.size() < 3 || 4 < vDeploymentParams.size()) {
531
- throw std::runtime_error("Version bits parameters malformed, expecting deployment:start:end[:min_activation_height]");
532
- }
533
- int64_t nStartTime, nTimeout;
534
- int min_activation_height = 0;
535
- if (!ParseInt64(vDeploymentParams[1], &nStartTime)) {
536
- throw std::runtime_error(strprintf("Invalid nStartTime (%s)", vDeploymentParams[1]));
537
- }
538
- if (!ParseInt64(vDeploymentParams[2], &nTimeout)) {
539
- throw std::runtime_error(strprintf("Invalid nTimeout (%s)", vDeploymentParams[2]));
540
- }
541
- if (vDeploymentParams.size() >= 4 && !ParseInt32(vDeploymentParams[3], &min_activation_height)) {
542
- throw std::runtime_error(strprintf("Invalid min_activation_height (%s)", vDeploymentParams[3]));
543
- }
544
- bool found = false;
545
- for (int j=0; j < (int)Consensus::MAX_VERSION_BITS_DEPLOYMENTS; ++j) {
546
- if (vDeploymentParams[0] == VersionBitsDeploymentInfo[j].name) {
547
- UpdateVersionBitsParameters(Consensus::DeploymentPos(j), nStartTime, nTimeout, min_activation_height);
548
- found = true;
549
- LogPrintf("Setting version bits activation parameters for %s to start=%ld, timeout=%ld, min_activation_height=%d\n", vDeploymentParams[0], nStartTime, nTimeout, min_activation_height);
550
- break;
551
- }
552
- }
553
- if (!found) {
554
- throw std::runtime_error(strprintf("Invalid deployment (%s)", vDeploymentParams[0]));
555
- }
556
- }
557
- }
516
+ }
558
517
 
559
518
  static std::unique_ptr<const CChainParams> globalChainParams;
560
519
 
src/chainparams.h CHANGED
@@ -93,6 +93,8 @@ public:
93
93
  }
94
94
 
95
95
  const CBlock& GenesisBlock() const { return genesis; }
96
+ /** Make miner wait to have peers to avoid wasting work */
97
+ bool MiningRequiresPeers() const { return fMiningRequiresPeers; }
96
98
  /** Default value for -checkmempool and -checkblockindex argument */
97
99
  bool DefaultConsistencyChecks() const { return fDefaultConsistencyChecks; }
98
100
  /** Policy: Filter transactions that do not match well-defined patterns */
@@ -104,8 +106,6 @@ public:
104
106
  uint64_t PruneAfterHeight() const { return nPruneAfterHeight; }
105
107
  /** Minimum free space (in GB) needed for data directory */
106
108
  uint64_t AssumedBlockchainSize() const { return m_assumed_blockchain_size; }
107
- /** Minimum free space (in GB) needed for data directory when pruned; Does not include prune target*/
108
- uint64_t AssumedChainStateSize() const { return m_assumed_chain_state_size; }
109
109
  /** Whether it is possible to mine blocks on demand (no retargeting) */
110
110
  bool MineBlocksOnDemand() const { return consensus.fPowNoRetargeting; }
111
111
  /** Return the network string */
@@ -130,13 +130,13 @@ protected:
130
130
  uint16_t nDefaultPort;
131
131
  uint64_t nPruneAfterHeight;
132
132
  uint64_t m_assumed_blockchain_size;
133
- uint64_t m_assumed_chain_state_size;
134
133
  std::vector<std::string> vSeeds;
135
134
  std::vector<unsigned char> base58Prefixes[MAX_BASE58_TYPES];
136
135
  std::string bech32_hrp;
137
136
  std::string strNetworkID;
138
137
  CBlock genesis;
139
138
  std::vector<uint8_t> vFixedSeeds;
139
+ bool fMiningRequiresPeers;
140
140
  bool fDefaultConsistencyChecks;
141
141
  bool fRequireStandard;
142
142
  bool m_is_test_chain;
src/chainparamsbase.cpp CHANGED
@@ -43,13 +43,13 @@ const CBaseChainParams& BaseParams()
43
43
  std::unique_ptr<CBaseChainParams> CreateBaseChainParams(const std::string& chain)
44
44
  {
45
45
  if (chain == CBaseChainParams::MAIN) {
46
- return std::make_unique<CBaseChainParams>("", 8332, 8334);
46
+ return std::make_unique<CBaseChainParams>("", 9902, 9903);
47
47
  } else if (chain == CBaseChainParams::TESTNET) {
48
- return std::make_unique<CBaseChainParams>("testnet3", 18332, 18334);
48
+ return std::make_unique<CBaseChainParams>("testnet3", 9904, 9905);
49
49
  } else if (chain == CBaseChainParams::SIGNET) {
50
50
  return std::make_unique<CBaseChainParams>("signet", 38332, 38334);
51
51
  } else if (chain == CBaseChainParams::REGTEST) {
52
- return std::make_unique<CBaseChainParams>("regtest", 18443, 18445);
52
+ return std::make_unique<CBaseChainParams>("regtest", 18443, 18444);
53
53
  }
54
54
  throw std::runtime_error(strprintf("%s: Unknown chain %s.", __func__, chain));
55
55
  }
src/clientversion.cpp CHANGED
@@ -18,6 +18,7 @@
18
18
  */
19
19
  const std::string CLIENT_NAME("Satoshi");
20
20
 
21
+ #define CLIENT_VERSION_SUFFIX " Coccinellidae"
21
22
 
22
23
  #ifdef HAVE_BUILD_INFO
23
24
  #include <obj/build.h>
@@ -34,7 +35,8 @@ const std::string CLIENT_NAME("Satoshi");
34
35
  #define BUILD_DESC BUILD_GIT_TAG
35
36
  #define BUILD_SUFFIX ""
36
37
  #else
37
- #define BUILD_DESC "v" PACKAGE_VERSION
38
+ #define BUILD_DESC "v" STRINGIZE(PEERCOIN_VERSION_MAJOR) "." STRINGIZE(PEERCOIN_VERSION_MINOR) \
39
+ "." STRINGIZE(PEERCOIN_VERSION_REVISION) "." STRINGIZE(PEERCOIN_VERSION_BUILD)
38
40
  #if CLIENT_VERSION_IS_RELEASE
39
41
  #define BUILD_SUFFIX ""
40
42
  #elif defined(BUILD_GIT_COMMIT)
@@ -53,7 +55,7 @@ static std::string FormatVersion(int nVersion)
53
55
 
54
56
  std::string FormatFullVersion()
55
57
  {
56
- static const std::string CLIENT_BUILD(BUILD_DESC BUILD_SUFFIX);
58
+ static const std::string CLIENT_BUILD(BUILD_DESC CLIENT_VERSION_SUFFIX);
57
59
  return CLIENT_BUILD;
58
60
  }
59
61
 
@@ -74,6 +76,8 @@ std::string FormatSubVersion(const std::string& name, int nClientVersion, const
74
76
  ss << ")";
75
77
  }
76
78
  ss << "/";
79
+ ss << "Peercoin:" << FormatVersion(PEERCOIN_VERSION);
80
+ ss << "(" << FormatFullVersion() << ")/";
77
81
  return ss.str();
78
82
  }
79
83
 
@@ -91,7 +95,7 @@ std::string CopyrightHolders(const std::string& strPrefix)
91
95
 
92
96
  std::string LicenseInfo()
93
97
  {
94
- const std::string URL_SOURCE_CODE = "<https://github.com/bitcoin/bitcoin>";
98
+ const std::string URL_SOURCE_CODE = "<https://github.com/peercoin/peercoin>";
95
99
 
96
100
  return CopyrightHolders(strprintf(_("Copyright (C) %i-%i").translated, 2009, COPYRIGHT_YEAR) + " ") + "\n" +
97
101
  "\n" +
src/clientversion.h CHANGED
@@ -12,7 +12,7 @@
12
12
  #endif //HAVE_CONFIG_H
13
13
 
14
14
  // Check that required client information is defined
15
- #if !defined(CLIENT_VERSION_MAJOR) || !defined(CLIENT_VERSION_MINOR) || !defined(CLIENT_VERSION_BUILD) || !defined(CLIENT_VERSION_IS_RELEASE) || !defined(COPYRIGHT_YEAR)
15
+ #if !defined(PEERCOIN_VERSION_MAJOR) || !defined(PEERCOIN_VERSION_MINOR) || !defined(PEERCOIN_VERSION_REVISION) || !defined(PEERCOIN_VERSION_BUILD)
16
16
  #error Client version information missing: version is not defined by bitcoin-config.h or in any other way
17
17
  #endif
18
18
 
@@ -35,6 +35,13 @@ static const int CLIENT_VERSION =
35
35
  + 100 * CLIENT_VERSION_MINOR
36
36
  + 1 * CLIENT_VERSION_BUILD;
37
37
 
38
+ // note: peercoin version is used for display purpose AND to accept alerts
39
+ static const int PEERCOIN_VERSION =
40
+ 1000000 * PEERCOIN_VERSION_MAJOR
41
+ + 10000 * PEERCOIN_VERSION_MINOR
42
+ + 100 * PEERCOIN_VERSION_REVISION
43
+ + 1 * PEERCOIN_VERSION_BUILD;
44
+
38
45
  extern const std::string CLIENT_NAME;
39
46
 
40
47
 
src/coins.cpp CHANGED
@@ -64,9 +64,10 @@ bool CCoinsViewCache::GetCoin(const COutPoint &outpoint, Coin &coin) const {
64
64
  return false;
65
65
  }
66
66
 
67
- void CCoinsViewCache::AddCoin(const COutPoint &outpoint, Coin&& coin, bool possible_overwrite) {
67
+ void CCoinsViewCache::AddCoin(const COutPoint &outpoint, Coin&& coin, bool possible_overwrite, bool skipZeroValue) {
68
68
  assert(!coin.IsSpent());
69
69
  if (coin.out.scriptPubKey.IsUnspendable()) return;
70
+ if (coin.out.nValue == 0 && skipZeroValue) return;
70
71
  CCoinsMap::iterator it;
71
72
  bool inserted;
72
73
  std::tie(it, inserted) = cacheCoins.emplace(std::piecewise_construct, std::forward_as_tuple(outpoint), std::tuple<>());
@@ -112,14 +113,14 @@ void CCoinsViewCache::EmplaceCoinInternalDANGER(COutPoint&& outpoint, Coin&& coi
112
113
  std::forward_as_tuple(std::move(coin), CCoinsCacheEntry::DIRTY));
113
114
  }
114
115
 
115
- void AddCoins(CCoinsViewCache& cache, const CTransaction &tx, int nHeight, bool check_for_overwrite) {
116
+ void AddCoins(CCoinsViewCache& cache, const CTransaction &tx, int nHeight, bool check_for_overwrite, bool skipZeroValue) {
116
117
  bool fCoinbase = tx.IsCoinBase();
117
118
  const uint256& txid = tx.GetHash();
118
119
  for (size_t i = 0; i < tx.vout.size(); ++i) {
119
120
  bool overwrite = check_for_overwrite ? cache.HaveCoin(COutPoint(txid, i)) : fCoinbase;
120
121
  // Coinbase transactions can always be overwritten, in order to correctly
121
122
  // deal with the pre-BIP30 occurrences of duplicate coinbase transactions.
122
- cache.AddCoin(COutPoint(txid, i), Coin(tx.vout[i], nHeight, fCoinbase), overwrite);
123
+ cache.AddCoin(COutPoint(txid, i), Coin(tx.vout[i], nHeight, fCoinbase, tx.IsCoinStake(), tx.nTime), overwrite, skipZeroValue);
123
124
  }
124
125
  }
125
126
 
src/coins.h CHANGED
@@ -39,29 +39,48 @@ public:
39
39
  //! at which height this containing transaction was included in the active block chain
40
40
  uint32_t nHeight : 31;
41
41
 
42
+ // peercoin: whether transaction is a coinstake
43
+ bool fCoinStake;
44
+
45
+ // peercoin: transaction timestamp
46
+ unsigned int nTime;
47
+
42
48
  //! construct a Coin from a CTxOut and height/coinbase information.
43
- Coin(CTxOut&& outIn, int nHeightIn, bool fCoinBaseIn) : out(std::move(outIn)), fCoinBase(fCoinBaseIn), nHeight(nHeightIn) {}
44
- Coin(const CTxOut& outIn, int nHeightIn, bool fCoinBaseIn) : out(outIn), fCoinBase(fCoinBaseIn),nHeight(nHeightIn) {}
49
+ Coin(CTxOut&& outIn, int nHeightIn, bool fCoinBaseIn, bool fCoinStakeIn, int nTimeIn) :
50
+ out(std::move(outIn)), fCoinBase(fCoinBaseIn), nHeight(nHeightIn), fCoinStake(fCoinStakeIn), nTime(nTimeIn) {}
51
+ Coin(const CTxOut& outIn, int nHeightIn, bool fCoinBaseIn, bool fCoinStakeIn, int nTimeIn) :
52
+ out(outIn), fCoinBase(fCoinBaseIn), nHeight(nHeightIn), fCoinStake(fCoinStakeIn), nTime(nTimeIn) {}
45
53
 
46
54
  void Clear() {
47
55
  out.SetNull();
48
56
  fCoinBase = false;
49
57
  nHeight = 0;
58
+ fCoinStake = false;
59
+ nTime = 0;
50
60
  }
51
61
 
52
62
  //! empty constructor
53
- Coin() : fCoinBase(false), nHeight(0) { }
63
+ Coin() : fCoinBase(false), nHeight(0), fCoinStake(false), nTime(0) { }
54
64
 
55
65
  bool IsCoinBase() const {
56
66
  return fCoinBase;
57
67
  }
58
68
 
69
+ bool IsCoinStake() const { // peercoin: coinstake
70
+ return fCoinStake;
71
+ }
72
+
59
73
  template<typename Stream>
60
74
  void Serialize(Stream &s) const {
61
75
  assert(!IsSpent());
62
76
  uint32_t code = nHeight * uint32_t{2} + fCoinBase;
63
77
  ::Serialize(s, VARINT(code));
64
78
  ::Serialize(s, Using<TxOutCompression>(out));
79
+ // peercoin flags
80
+ unsigned int nFlag = fCoinStake? 1 : 0;
81
+ ::Serialize(s, VARINT(nFlag));
82
+ // peercoin transaction timestamp
83
+ ::Serialize(s, VARINT(nTime));
65
84
  }
66
85
 
67
86
  template<typename Stream>
@@ -71,6 +90,12 @@ public:
71
90
  nHeight = code >> 1;
72
91
  fCoinBase = code & 1;
73
92
  ::Unserialize(s, Using<TxOutCompression>(out));
93
+ // peercoin flags
94
+ unsigned int nFlag = 0;
95
+ ::Unserialize(s, VARINT(nFlag));
96
+ fCoinStake = nFlag & 1;
97
+ // peercoin transaction timestamp
98
+ ::Unserialize(s, VARINT(nTime));
74
99
  }
75
100
 
76
101
  /** Either this coin never existed (see e.g. coinEmpty in coins.cpp), or it
@@ -264,7 +289,7 @@ public:
264
289
  * Add a coin. Set possible_overwrite to true if an unspent version may
265
290
  * already exist in the cache.
266
291
  */
267
- void AddCoin(const COutPoint& outpoint, Coin&& coin, bool possible_overwrite);
292
+ void AddCoin(const COutPoint& outpoint, Coin&& coin, bool possible_overwrite, bool skipZeroValue = false);
268
293
 
269
294
  /**
270
295
  * Emplace a coin into cacheCoins without performing any checks, marking
@@ -325,7 +350,7 @@ private:
325
350
  //! an overwrite.
326
351
  // TODO: pass in a boolean to limit these possible overwrites to known
327
352
  // (pre-BIP34) cases.
328
- void AddCoins(CCoinsViewCache& cache, const CTransaction& tx, int nHeight, bool check = false);
353
+ void AddCoins(CCoinsViewCache& cache, const CTransaction& tx, int nHeight, bool check = false, bool skipZeroValue = false);
329
354
 
330
355
  //! Utility function to find any unspent output with a given txid.
331
356
  //! This function can be quite expensive because in the event of a transaction
src/consensus/amount.h CHANGED
@@ -7,12 +7,22 @@
7
7
  #define BITCOIN_CONSENSUS_AMOUNT_H
8
8
 
9
9
  #include <cstdint>
10
+ #include <string>
10
11
 
11
12
  /** Amount in satoshis (Can be negative) */
12
13
  typedef int64_t CAmount;
13
14
 
14
- /** The amount of satoshis in one BTC. */
15
- static constexpr CAmount COIN = 100000000;
15
+ static constexpr CAmount COIN = 1000000;
16
+ static constexpr CAmount CENT = 10000;
17
+
18
+ static const CAmount MIN_TX_FEE_PREV7 = CENT;
19
+ static const CAmount MIN_TX_FEE = CENT / 10;
20
+ static const CAmount PERKB_TX_FEE = CENT;
21
+ static const CAmount MIN_TXOUT_AMOUNT = CENT;
22
+ static const CAmount MAX_MINT_PROOF_OF_WORK = 9999 * COIN;
23
+ static const CAmount MAX_MINT_PROOF_OF_WORK_V10 = 50 * COIN;
24
+ static const std::string CURRENCY_UNIT = "PPC";
25
+ static const std::string CURRENCY_ATOM = "sat"; // One indivisible minimum value unit
16
26
 
17
27
  /** No amount larger than this (in satoshi) is valid.
18
28
  *
src/consensus/params.h CHANGED
@@ -33,52 +33,16 @@ enum DeploymentPos : uint16_t {
33
33
  };
34
34
  constexpr bool ValidDeployment(DeploymentPos dep) { return dep < MAX_VERSION_BITS_DEPLOYMENTS; }
35
35
 
36
- /**
37
- * Struct for each individual consensus rule change using BIP9.
38
- */
39
- struct BIP9Deployment {
40
- /** Bit position to select the particular bit in nVersion. */
41
- int bit;
42
- /** Start MedianTime for version bits miner confirmation. Can be a date in the past */
43
- int64_t nStartTime;
44
- /** Timeout/expiry MedianTime for the deployment attempt. */
45
- int64_t nTimeout;
46
- /** If lock in occurs, delay activation until at least this block
47
- * height. Note that activation will only occur on a retarget
48
- * boundary.
49
- */
50
- int min_activation_height{0};
51
-
52
- /** Constant for nTimeout very far in the future. */
53
- static constexpr int64_t NO_TIMEOUT = std::numeric_limits<int64_t>::max();
54
-
55
- /** Special value for nStartTime indicating that the deployment is always active.
56
- * This is useful for testing, as it means tests don't need to deal with the activation
57
- * process (which takes at least 3 BIP9 intervals). Only tests that specifically test the
58
- * behaviour during activation cannot use this. */
59
- static constexpr int64_t ALWAYS_ACTIVE = -1;
60
-
61
- /** Special value for nStartTime indicating that the deployment is never active.
62
- * This is useful for integrating the code changes for a new feature
63
- * prior to deploying it on some or all networks. */
64
- static constexpr int64_t NEVER_ACTIVE = -2;
65
- };
66
-
67
36
  /**
68
37
  * Parameters that influence chain consensus.
69
38
  */
70
39
  struct Params {
71
40
  uint256 hashGenesisBlock;
72
- int nSubsidyHalvingInterval;
73
41
  /* Block hash that is excepted from BIP16 enforcement */
74
42
  uint256 BIP16Exception;
75
43
  /** Block height and hash at which BIP34 becomes active */
76
44
  int BIP34Height;
77
45
  uint256 BIP34Hash;
78
- /** Block height at which BIP65 becomes active */
79
- int BIP65Height;
80
- /** Block height at which BIP66 becomes active */
81
- int BIP66Height;
82
46
  /** Block height at which CSV (BIP68, BIP112 and BIP113) becomes active */
83
47
  int CSVHeight;
84
48
  /** Block height at which Segwit (BIP141, BIP143 and BIP147) becomes active.
@@ -90,19 +54,16 @@ struct Params {
90
54
  int MinBIP9WarningHeight;
91
55
  /**
92
56
  * Minimum blocks including miner confirmation of the total of 2016 blocks in a retargeting period,
93
- * (nPowTargetTimespan / nPowTargetSpacing) which is also used for BIP9 deployments.
57
+ * (nPowTargetTimespan / nPowTargetSpacing)
94
58
  * Examples: 1916 for 95%, 1512 for testchains.
95
59
  */
96
60
  uint32_t nRuleChangeActivationThreshold;
97
61
  uint32_t nMinerConfirmationWindow;
98
- BIP9Deployment vDeployments[MAX_VERSION_BITS_DEPLOYMENTS];
99
62
  /** Proof of work parameters */
100
63
  uint256 powLimit;
101
64
  bool fPowAllowMinDifficultyBlocks;
102
65
  bool fPowNoRetargeting;
103
66
  int64_t nPowTargetSpacing;
104
- int64_t nPowTargetTimespan;
105
- int64_t DifficultyAdjustmentInterval() const { return nPowTargetTimespan / nPowTargetSpacing; }
106
67
  /** The best chain should have at least this much work */
107
68
  uint256 nMinimumChainWork;
108
69
  /** By default assume that the signatures in ancestors of this block are valid */
@@ -114,23 +75,15 @@ struct Params {
114
75
  */
115
76
  bool signet_blocks{false};
116
77
  std::vector<uint8_t> signet_challenge;
117
-
118
- int DeploymentHeight(BuriedDeployment dep) const
119
- {
120
- switch (dep) {
121
- case DEPLOYMENT_HEIGHTINCB:
122
- return BIP34Height;
123
- case DEPLOYMENT_CLTV:
124
- return BIP65Height;
125
- case DEPLOYMENT_DERSIG:
126
- return BIP66Height;
127
- case DEPLOYMENT_CSV:
128
- return CSVHeight;
129
- case DEPLOYMENT_SEGWIT:
130
- return SegwitHeight;
131
- } // no default case, so the compiler can warn about missing cases
132
- return std::numeric_limits<int>::max();
133
- }
78
+ /** peercoin stuff */
79
+ uint256 bnInitialHashTarget;
80
+ int64_t nStakeTargetSpacing;
81
+ int64_t nTargetSpacingWorkMax;
82
+ int64_t nTargetTimespan;
83
+ int64_t nStakeMinAge;
84
+ int64_t nStakeMaxAge;
85
+ int64_t nModifierInterval;
86
+ int nCoinbaseMaturity; // Coinbase transaction outputs can only be spent after this number of new blocks (network rule)
134
87
  };
135
88
 
136
89
  } // namespace Consensus
src/consensus/tx_check.cpp CHANGED
@@ -7,6 +7,12 @@
7
7
  #include <consensus/amount.h>
8
8
  #include <primitives/transaction.h>
9
9
  #include <consensus/validation.h>
10
+ #include <chainparams.h>
11
+
12
+ bool IsZeroAllowed(const unsigned int nTimeTx)
13
+ {
14
+ return (nTimeTx >= 1447700000 ); // very crude approximation to prevent linking with kernel.cpp
15
+ }
10
16
 
11
17
  bool CheckTransaction(const CTransaction& tx, TxValidationState& state)
12
18
  {
@@ -30,6 +36,10 @@ bool CheckTransaction(const CTransaction& tx, TxValidationState& state)
30
36
  nValueOut += txout.nValue;
31
37
  if (!MoneyRange(nValueOut))
32
38
  return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-txns-txouttotal-toolarge");
39
+ // peercoin: enforce minimum output amount
40
+ if ((!txout.IsEmpty()) && txout.nValue < MIN_TXOUT_AMOUNT &&
41
+ (tx.nVersion < 3 && !(IsZeroAllowed(tx.nTime) && (txout.nValue == 0))))
42
+ return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-txns-txoutvalue-belowminimum");
33
43
  }
34
44
 
35
45
  // Check for duplicate inputs (see CVE-2018-17144)
src/consensus/tx_verify.cpp CHANGED
@@ -11,6 +11,9 @@
11
11
  #include <consensus/validation.h>
12
12
  #include <primitives/transaction.h>
13
13
  #include <script/interpreter.h>
14
+ #include <kernel.h>
15
+ #include <validation.h> // GetCoinAge()
16
+
14
17
  #include <util/moneystr.h>
15
18
 
16
19
  bool IsFinalTx(const CTransaction &tx, int nBlockHeight, int64_t nBlockTime)
@@ -164,7 +167,7 @@ int64_t GetTransactionSigOpCost(const CTransaction& tx, const CCoinsViewCache& i
164
167
  return nSigOps;
165
168
  }
166
169
 
167
- bool Consensus::CheckTxInputs(const CTransaction& tx, TxValidationState& state, const CCoinsViewCache& inputs, int nSpendHeight, CAmount& txfee)
170
+ bool Consensus::CheckTxInputs(const CTransaction& tx, TxValidationState& state, const CCoinsViewCache& inputs, int nSpendHeight, CAmount& txfee, const Consensus::Params& params, unsigned int nTimeTx, uint64_t nMoneySupply)
168
171
  {
169
172
  // are the actual inputs available?
170
173
  if (!inputs.HaveInputs(tx)) {
@@ -179,11 +182,15 @@ bool Consensus::CheckTxInputs(const CTransaction& tx, TxValidationState& state,
179
182
  assert(!coin.IsSpent());
180
183
 
181
184
  // If prev is coinbase, check that it's matured
182
- if (coin.IsCoinBase() && nSpendHeight - coin.nHeight < COINBASE_MATURITY) {
183
- return state.Invalid(TxValidationResult::TX_PREMATURE_SPEND, "bad-txns-premature-spend-of-coinbase",
185
+ if ((coin.IsCoinBase() || coin.IsCoinStake()) && nSpendHeight - coin.nHeight < params.nCoinbaseMaturity) {
186
+ return state.Invalid(TxValidationResult::TX_PREMATURE_SPEND, "bad-txns-premature-spend-of-coinbase/coinstake",
184
187
  strprintf("tried to spend coinbase at depth %d", nSpendHeight - coin.nHeight));
185
188
  }
186
189
 
190
+ // peercoin: check transaction timestamp
191
+ if (coin.nTime > nTimeTx)
192
+ return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-txns-spent-too-early", strprintf("%s : transaction timestamp earlier than input transaction", __func__));
193
+
187
194
  // Check for negative or overflow input values
188
195
  nValueIn += coin.out.nValue;
189
196
  if (!MoneyRange(coin.out.nValue) || !MoneyRange(nValueIn)) {
@@ -191,18 +198,52 @@ bool Consensus::CheckTxInputs(const CTransaction& tx, TxValidationState& state,
191
198
  }
192
199
  }
193
200
 
194
- const CAmount value_out = tx.GetValueOut();
195
- if (nValueIn < value_out) {
196
- return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-txns-in-belowout",
197
- strprintf("value in (%s) < value out (%s)", FormatMoney(nValueIn), FormatMoney(value_out)));
201
+ if (tx.IsCoinStake())
202
+ {
203
+ // peercoin: coin stake tx earns reward instead of paying fee
204
+ uint64_t nCoinAge;
205
+ if (!GetCoinAge(tx, inputs, nCoinAge, nTimeTx))
206
+ return state.Invalid(TxValidationResult::TX_CONSENSUS, "unable to get coin age for coinstake");
207
+ CAmount nStakeReward = tx.GetValueOut() - nValueIn;
208
+ CAmount nCoinstakeCost = (GetMinFee(tx, nTimeTx) < PERKB_TX_FEE) ? 0 : (GetMinFee(tx, nTimeTx) - PERKB_TX_FEE);
209
+ if (nMoneySupply && nStakeReward > GetProofOfStakeReward(nCoinAge, nTimeTx, nMoneySupply) - nCoinstakeCost)
210
+ return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-txns-coinstake-too-large");
198
211
  }
199
-
200
- // Tally transaction fees
201
- const CAmount txfee_aux = nValueIn - value_out;
202
- if (!MoneyRange(txfee_aux)) {
203
- return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-txns-fee-outofrange");
212
+ else
213
+ {
214
+ const CAmount value_out = tx.GetValueOut();
215
+ if (nValueIn < value_out) {
216
+ return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-txns-in-belowout",
217
+ strprintf("value in (%s) < value out (%s)", FormatMoney(nValueIn), FormatMoney(value_out)));
218
+ }
219
+ // Tally transaction fees
220
+ const CAmount txfee_aux = nValueIn - value_out;
221
+ if (!MoneyRange(txfee_aux)) {
222
+ return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-txns-fee-outofrange");
223
+ }
224
+ // peercoin: enforce transaction fees for every block
225
+ if (txfee_aux < GetMinFee(tx, nTimeTx))
226
+ return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-txns-fee-not-enough");
227
+ txfee = txfee_aux;
204
228
  }
205
-
206
- txfee = txfee_aux;
207
229
  return true;
208
230
  }
231
+
232
+ CAmount GetMinFee(const CTransaction& tx, unsigned int nTimeTx)
233
+ {
234
+ size_t nBytes = ::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION);
235
+ return GetMinFee(nBytes, nTimeTx);
236
+ }
237
+
238
+ CAmount GetMinFee(size_t nBytes, uint32_t nTime)
239
+ {
240
+ CAmount nMinFee;
241
+ if (IsProtocolV07(nTime) || !nTime) // RFC-0007
242
+ nMinFee = (nBytes < 100) ? MIN_TX_FEE : (CAmount)(nBytes * (PERKB_TX_FEE / 1000));
243
+ else
244
+ nMinFee = (1 + (CAmount)nBytes / 1000) * PERKB_TX_FEE;
245
+
246
+ if (!MoneyRange(nMinFee))
247
+ nMinFee = MAX_MONEY;
248
+ return nMinFee;
249
+ }
src/consensus/tx_verify.h CHANGED
@@ -18,13 +18,14 @@ class TxValidationState;
18
18
  /** Transaction validation functions */
19
19
 
20
20
  namespace Consensus {
21
+ struct Params;
21
22
  /**
22
23
  * Check whether all inputs of this transaction are valid (no double spends and amounts)
23
24
  * This does not modify the UTXO set. This does not check scripts and sigs.
24
25
  * @param[out] txfee Set to the transaction fee if successful.
25
26
  * Preconditions: tx.IsCoinBase() is false.
26
27
  */
27
- [[nodiscard]] bool CheckTxInputs(const CTransaction& tx, TxValidationState& state, const CCoinsViewCache& inputs, int nSpendHeight, CAmount& txfee);
28
+ bool CheckTxInputs(const CTransaction& tx, TxValidationState& state, const CCoinsViewCache& inputs, int nSpendHeight, CAmount& txfee, const Consensus::Params& params, unsigned int nTimeTx, uint64_t nMoneySupply=0);
28
29
  } // namespace Consensus
29
30
 
30
31
  /** Auxiliary functions for transaction validation (ideally should not be exposed) */
@@ -75,4 +76,8 @@ bool EvaluateSequenceLocks(const CBlockIndex& block, std::pair<int, int64_t> loc
75
76
  */
76
77
  bool SequenceLocks(const CTransaction &tx, int flags, std::vector<int>& prevHeights, const CBlockIndex& block);
77
78
 
79
+ // peercoin: minimum fee for transaction to be accepted in a blockchain.
80
+ CAmount GetMinFee(const CTransaction& tx, unsigned int nTimeTx);
81
+ CAmount GetMinFee(size_t nBytes, uint32_t nTime);
82
+
78
83
  #endif // BITCOIN_CONSENSUS_TX_VERIFY_H
src/core_write.cpp CHANGED
@@ -29,7 +29,7 @@ UniValue ValueFromAmount(const CAmount amount)
29
29
  remainder = -remainder;
30
30
  }
31
31
  return UniValue(UniValue::VNUM,
32
- strprintf("%s%d.%08d", amount < 0 ? "-" : "", quotient, remainder));
32
+ strprintf("%s%d.%06d", amount < 0 ? "-" : "", quotient, remainder));
33
33
  }
34
34
 
35
35
  std::string FormatScript(const CScript& script)
@@ -174,6 +174,7 @@ void TxToUniv(const CTransaction& tx, const uint256& hashBlock, UniValue& entry,
174
174
  // Transaction version is actually unsigned in consensus checks, just signed in memory,
175
175
  // so cast to unsigned before giving it to the user.
176
176
  entry.pushKV("version", static_cast<int64_t>(static_cast<uint32_t>(tx.nVersion)));
177
+ entry.pushKV("time", (int64_t)tx.nTime);
177
178
  entry.pushKV("size", (int)::GetSerializeSize(tx, PROTOCOL_VERSION));
178
179
  entry.pushKV("vsize", (GetTransactionWeight(tx) + WITNESS_SCALE_FACTOR - 1) / WITNESS_SCALE_FACTOR);
179
180
  entry.pushKV("weight", GetTransactionWeight(tx));
@@ -252,8 +253,10 @@ void TxToUniv(const CTransaction& tx, const uint256& hashBlock, UniValue& entry,
252
253
 
253
254
  if (have_undo) {
254
255
  const CAmount fee = amt_total_in - amt_total_out;
255
- CHECK_NONFATAL(MoneyRange(fee));
256
- entry.pushKV("fee", ValueFromAmount(fee));
256
+ if (fee > 0)
257
+ entry.pushKV("fee", ValueFromAmount(fee));
258
+ else
259
+ entry.pushKV("reward", ValueFromAmount(-fee));
257
260
  }
258
261
 
259
262
  if (!hashBlock.IsNull())
src/deploymentstatus.cpp DELETED
@@ -1,34 +0,0 @@
1
- // Copyright (c) 2020-2021 The Bitcoin Core developers
2
- // Distributed under the MIT software license, see the accompanying
3
- // file COPYING or http://www.opensource.org/licenses/mit-license.php.
4
-
5
- #include <deploymentstatus.h>
6
-
7
- #include <consensus/params.h>
8
- #include <versionbits.h>
9
-
10
- #include <type_traits>
11
-
12
- VersionBitsCache g_versionbitscache;
13
-
14
- /* Basic sanity checking for BuriedDeployment/DeploymentPos enums and
15
- * ValidDeployment check */
16
-
17
- static_assert(ValidDeployment(Consensus::DEPLOYMENT_TESTDUMMY), "sanity check of DeploymentPos failed (TESTDUMMY not valid)");
18
- static_assert(!ValidDeployment(Consensus::MAX_VERSION_BITS_DEPLOYMENTS), "sanity check of DeploymentPos failed (MAX value considered valid)");
19
- static_assert(!ValidDeployment(static_cast<Consensus::BuriedDeployment>(Consensus::DEPLOYMENT_TESTDUMMY)), "sanity check of BuriedDeployment failed (overlaps with DeploymentPos)");
20
-
21
- /* ValidDeployment only checks upper bounds for ensuring validity.
22
- * This checks that the lowest possible value or the type is also a
23
- * (specific) valid deployment so that lower bounds don't need to be checked.
24
- */
25
-
26
- template<typename T, T x>
27
- static constexpr bool is_minimum()
28
- {
29
- using U = typename std::underlying_type<T>::type;
30
- return x == std::numeric_limits<U>::min();
31
- }
32
-
33
- static_assert(is_minimum<Consensus::BuriedDeployment, Consensus::DEPLOYMENT_HEIGHTINCB>(), "heightincb is not minimum value for BuriedDeployment");
34
- static_assert(is_minimum<Consensus::DeploymentPos, Consensus::DEPLOYMENT_TESTDUMMY>(), "testdummy is not minimum value for DeploymentPos");
src/deploymentstatus.h DELETED
@@ -1,55 +0,0 @@
1
- // Copyright (c) 2020-2021 The Bitcoin Core developers
2
- // Distributed under the MIT software license, see the accompanying
3
- // file COPYING or http://www.opensource.org/licenses/mit-license.php.
4
-
5
- #ifndef BITCOIN_DEPLOYMENTSTATUS_H
6
- #define BITCOIN_DEPLOYMENTSTATUS_H
7
-
8
- #include <chain.h>
9
- #include <versionbits.h>
10
-
11
- #include <limits>
12
-
13
- /** Global cache for versionbits deployment status */
14
- extern VersionBitsCache g_versionbitscache;
15
-
16
- /** Determine if a deployment is active for the next block */
17
- inline bool DeploymentActiveAfter(const CBlockIndex* pindexPrev, const Consensus::Params& params, Consensus::BuriedDeployment dep)
18
- {
19
- assert(Consensus::ValidDeployment(dep));
20
- return (pindexPrev == nullptr ? 0 : pindexPrev->nHeight + 1) >= params.DeploymentHeight(dep);
21
- }
22
-
23
- inline bool DeploymentActiveAfter(const CBlockIndex* pindexPrev, const Consensus::Params& params, Consensus::DeploymentPos dep)
24
- {
25
- assert(Consensus::ValidDeployment(dep));
26
- return ThresholdState::ACTIVE == g_versionbitscache.State(pindexPrev, params, dep);
27
- }
28
-
29
- /** Determine if a deployment is active for this block */
30
- inline bool DeploymentActiveAt(const CBlockIndex& index, const Consensus::Params& params, Consensus::BuriedDeployment dep)
31
- {
32
- assert(Consensus::ValidDeployment(dep));
33
- return index.nHeight >= params.DeploymentHeight(dep);
34
- }
35
-
36
- inline bool DeploymentActiveAt(const CBlockIndex& index, const Consensus::Params& params, Consensus::DeploymentPos dep)
37
- {
38
- assert(Consensus::ValidDeployment(dep));
39
- return DeploymentActiveAfter(index.pprev, params, dep);
40
- }
41
-
42
- /** Determine if a deployment is enabled (can ever be active) */
43
- inline bool DeploymentEnabled(const Consensus::Params& params, Consensus::BuriedDeployment dep)
44
- {
45
- assert(Consensus::ValidDeployment(dep));
46
- return params.DeploymentHeight(dep) != std::numeric_limits<int>::max();
47
- }
48
-
49
- inline bool DeploymentEnabled(const Consensus::Params& params, Consensus::DeploymentPos dep)
50
- {
51
- assert(Consensus::ValidDeployment(dep));
52
- return params.vDeployments[dep].nStartTime != Consensus::BIP9Deployment::NEVER_ACTIVE;
53
- }
54
-
55
- #endif // BITCOIN_DEPLOYMENTSTATUS_H
src/dummywallet.cpp CHANGED
@@ -35,7 +35,6 @@ void DummyWalletInit::AddWalletOptions(ArgsManager& argsman) const
35
35
  "-fallbackfee=<amt>",
36
36
  "-keypool=<n>",
37
37
  "-maxapsfee=<n>",
38
- "-maxtxfee=<amt>",
39
38
  "-mintxfee=<amt>",
40
39
  "-paytxfee=<amt>",
41
40
  "-signer=<cmd>",
@@ -45,7 +44,6 @@ void DummyWalletInit::AddWalletOptions(ArgsManager& argsman) const
45
44
  "-walletbroadcast",
46
45
  "-walletdir=<dir>",
47
46
  "-walletnotify=<cmd>",
48
- "-walletrbf",
49
47
  "-dblogsize=<n>",
50
48
  "-flushwallet",
51
49
  "-privdb",
src/hash.cpp CHANGED
@@ -94,3 +94,12 @@ CHashWriter TaggedHash(const std::string& tag)
94
94
  writer << taghash << taghash;
95
95
  return writer;
96
96
  }
97
+
98
+ int32_t peercoinRandseed;
99
+ int univHash(const uint256 &x) {
100
+ int h = peercoinRandseed >> 20;
101
+ const uint32_t *p = x.GetDataPtr();
102
+ for(int i = 0; i < 8; i++)
103
+ h ^= (p[i] >> (h & 0xf)) + (peercoinRandseed >> i);
104
+ return (h + (h >> 16)) & 1023; // 2^n - 1
105
+ }
src/hash.h CHANGED
@@ -212,4 +212,7 @@ void BIP32Hash(const ChainCode &chainCode, unsigned int nChild, unsigned char he
212
212
  */
213
213
  CHashWriter TaggedHash(const std::string& tag);
214
214
 
215
+ extern int32_t peercoinRandseed;
216
+ int univHash(const uint256 &x);
217
+
215
218
  #endif // BITCOIN_HASH_H
src/index/base.cpp CHANGED
@@ -105,7 +105,7 @@ bool BaseIndex::Init()
105
105
  }
106
106
  }
107
107
  if (prune_violation) {
108
- return InitError(strprintf(Untranslated("%s best block of the index goes beyond pruned data. Please disable the index or reindex (which will download the whole blockchain again)"), GetName()));
108
+ return InitError(strprintf(Untranslated("%s best block of the index goes beyond pruned data. Please disable the index or reindex (which will download the whole blockchain again)"), GetName())); // peercoin: should never happen
109
109
  }
110
110
  }
111
111
  return true;
src/index/coinstatsindex.cpp CHANGED
@@ -112,8 +112,8 @@ CoinStatsIndex::CoinStatsIndex(size_t n_cache_size, bool f_memory, bool f_wipe)
112
112
  bool CoinStatsIndex::WriteBlock(const CBlock& block, const CBlockIndex* pindex)
113
113
  {
114
114
  CBlockUndo block_undo;
115
- const CAmount block_subsidy{GetBlockSubsidy(pindex->nHeight, Params().GetConsensus())};
116
- m_total_subsidy += block_subsidy;
115
+ //const CAmount block_subsidy{GetBlockSubsidy(pindex->nHeight, Params().GetConsensus())};
116
+ //m_total_subsidy += block_subsidy;
117
117
 
118
118
  // Ignore genesis block
119
119
  if (pindex->nHeight > 0) {
@@ -147,14 +147,14 @@ bool CoinStatsIndex::WriteBlock(const CBlock& block, const CBlockIndex* pindex)
147
147
 
148
148
  // Skip duplicate txid coinbase transactions (BIP30).
149
149
  if (is_bip30_block && tx->IsCoinBase()) {
150
- m_total_unspendable_amount += block_subsidy;
151
- m_total_unspendables_bip30 += block_subsidy;
150
+ //m_total_unspendable_amount += block_subsidy;
151
+ //m_total_unspendables_bip30 += block_subsidy;
152
152
  continue;
153
153
  }
154
154
 
155
155
  for (uint32_t j = 0; j < tx->vout.size(); ++j) {
156
156
  const CTxOut& out{tx->vout[j]};
157
- Coin coin{out, pindex->nHeight, tx->IsCoinBase()};
157
+ Coin coin{out, pindex->nHeight, tx->IsCoinBase(), tx->IsCoinStake(), (int)tx->nTime};
158
158
  COutPoint outpoint{tx->GetHash(), j};
159
159
 
160
160
  // Skip unspendable coins
@@ -197,17 +197,17 @@ bool CoinStatsIndex::WriteBlock(const CBlock& block, const CBlockIndex* pindex)
197
197
  }
198
198
  } else {
199
199
  // genesis block
200
- m_total_unspendable_amount += block_subsidy;
201
- m_total_unspendables_genesis_block += block_subsidy;
200
+ //m_total_unspendable_amount += block_subsidy;
201
+ //m_total_unspendables_genesis_block += block_subsidy;
202
202
  }
203
203
 
204
204
  // If spent prevouts + block subsidy are still a higher amount than
205
205
  // new outputs + coinbase + current unspendable amount this means
206
206
  // the miner did not claim the full block reward. Unclaimed block
207
207
  // rewards are also unspendable.
208
- const CAmount unclaimed_rewards{(m_total_prevout_spent_amount + m_total_subsidy) - (m_total_new_outputs_ex_coinbase_amount + m_total_coinbase_amount + m_total_unspendable_amount)};
209
- m_total_unspendable_amount += unclaimed_rewards;
210
- m_total_unspendables_unclaimed_rewards += unclaimed_rewards;
208
+ //const CAmount unclaimed_rewards{(m_total_prevout_spent_amount + m_total_subsidy) - (m_total_new_outputs_ex_coinbase_amount + m_total_coinbase_amount + m_total_unspendable_amount)};
209
+ //m_total_unspendable_amount += unclaimed_rewards;
210
+ //m_total_unspendables_unclaimed_rewards += unclaimed_rewards;
211
211
 
212
212
  std::pair<uint256, DBVal> value;
213
213
  value.first = pindex->GetBlockHash();
@@ -215,14 +215,14 @@ bool CoinStatsIndex::WriteBlock(const CBlock& block, const CBlockIndex* pindex)
215
215
  value.second.bogo_size = m_bogo_size;
216
216
  value.second.total_amount = m_total_amount;
217
217
  value.second.total_subsidy = m_total_subsidy;
218
- value.second.total_unspendable_amount = m_total_unspendable_amount;
218
+ //value.second.total_unspendable_amount = m_total_unspendable_amount;
219
219
  value.second.total_prevout_spent_amount = m_total_prevout_spent_amount;
220
220
  value.second.total_new_outputs_ex_coinbase_amount = m_total_new_outputs_ex_coinbase_amount;
221
221
  value.second.total_coinbase_amount = m_total_coinbase_amount;
222
- value.second.total_unspendables_genesis_block = m_total_unspendables_genesis_block;
223
- value.second.total_unspendables_bip30 = m_total_unspendables_bip30;
222
+ //value.second.total_unspendables_genesis_block = m_total_unspendables_genesis_block;
223
+ //value.second.total_unspendables_bip30 = m_total_unspendables_bip30;
224
224
  value.second.total_unspendables_scripts = m_total_unspendables_scripts;
225
- value.second.total_unspendables_unclaimed_rewards = m_total_unspendables_unclaimed_rewards;
225
+ //value.second.total_unspendables_unclaimed_rewards = m_total_unspendables_unclaimed_rewards;
226
226
 
227
227
  uint256 out;
228
228
  m_muhash.Finalize(out);
@@ -374,15 +374,15 @@ bool CoinStatsIndex::Init()
374
374
  m_transaction_output_count = entry.transaction_output_count;
375
375
  m_bogo_size = entry.bogo_size;
376
376
  m_total_amount = entry.total_amount;
377
- m_total_subsidy = entry.total_subsidy;
378
- m_total_unspendable_amount = entry.total_unspendable_amount;
377
+ //m_total_subsidy = entry.total_subsidy;
378
+ //m_total_unspendable_amount = entry.total_unspendable_amount;
379
379
  m_total_prevout_spent_amount = entry.total_prevout_spent_amount;
380
380
  m_total_new_outputs_ex_coinbase_amount = entry.total_new_outputs_ex_coinbase_amount;
381
381
  m_total_coinbase_amount = entry.total_coinbase_amount;
382
- m_total_unspendables_genesis_block = entry.total_unspendables_genesis_block;
383
- m_total_unspendables_bip30 = entry.total_unspendables_bip30;
382
+ //m_total_unspendables_genesis_block = entry.total_unspendables_genesis_block;
383
+ //m_total_unspendables_bip30 = entry.total_unspendables_bip30;
384
384
  m_total_unspendables_scripts = entry.total_unspendables_scripts;
385
- m_total_unspendables_unclaimed_rewards = entry.total_unspendables_unclaimed_rewards;
385
+ //m_total_unspendables_unclaimed_rewards = entry.total_unspendables_unclaimed_rewards;
386
386
  }
387
387
 
388
388
  return true;
@@ -394,8 +394,8 @@ bool CoinStatsIndex::ReverseBlock(const CBlock& block, const CBlockIndex* pindex
394
394
  CBlockUndo block_undo;
395
395
  std::pair<uint256, DBVal> read_out;
396
396
 
397
- const CAmount block_subsidy{GetBlockSubsidy(pindex->nHeight, Params().GetConsensus())};
398
- m_total_subsidy -= block_subsidy;
397
+ //const CAmount block_subsidy{GetBlockSubsidy(pindex->nHeight, Params().GetConsensus())};
398
+ //m_total_subsidy -= block_subsidy;
399
399
 
400
400
  // Ignore genesis block
401
401
  if (pindex->nHeight > 0) {
@@ -426,7 +426,7 @@ bool CoinStatsIndex::ReverseBlock(const CBlock& block, const CBlockIndex* pindex
426
426
  for (uint32_t j = 0; j < tx->vout.size(); ++j) {
427
427
  const CTxOut& out{tx->vout[j]};
428
428
  COutPoint outpoint{tx->GetHash(), j};
429
- Coin coin{out, pindex->nHeight, tx->IsCoinBase()};
429
+ Coin coin{out, pindex->nHeight, tx->IsCoinBase(), tx->IsCoinStake(), (int)tx->nTime};
430
430
 
431
431
  // Skip unspendable coins
432
432
  if (coin.out.scriptPubKey.IsUnspendable()) {
src/index/txindex.cpp CHANGED
@@ -100,3 +100,8 @@ bool TxIndex::FindTx(const uint256& tx_hash, uint256& block_hash, CTransactionRe
100
100
  block_hash = header.GetHash();
101
101
  return true;
102
102
  }
103
+
104
+ bool TxIndex::FindTxPosition(const uint256& txid, CDiskTxPos& pos) const
105
+ {
106
+ return m_db->ReadTxPos(txid, pos);
107
+ }
src/index/txindex.h CHANGED
@@ -6,6 +6,8 @@
6
6
  #define BITCOIN_INDEX_TXINDEX_H
7
7
 
8
8
  #include <index/base.h>
9
+ #include <index/disktxpos.h>
10
+ #include <primitives/block.h>
9
11
 
10
12
  /**
11
13
  * TxIndex is used to look up transactions included in the blockchain by hash.
@@ -41,6 +43,9 @@ public:
41
43
  /// @param[out] tx The transaction itself.
42
44
  /// @return true if transaction is found, false otherwise
43
45
  bool FindTx(const uint256& tx_hash, uint256& block_hash, CTransactionRef& tx) const;
46
+
47
+ bool FindTxPosition(const uint256& txid, CDiskTxPos& pos) const;
48
+ std::map<uint256,std::pair<CBlockHeader,CTransactionRef>> cachedTxs;
44
49
  };
45
50
 
46
51
  /// The global transaction index, used in GetTransaction. May be null.
src/init.cpp CHANGED
@@ -16,7 +16,6 @@
16
16
  #include <chainparams.h>
17
17
  #include <compat/sanity.h>
18
18
  #include <consensus/amount.h>
19
- #include <deploymentstatus.h>
20
19
  #include <fs.h>
21
20
  #include <hash.h>
22
21
  #include <httprpc.h>
@@ -39,8 +38,6 @@
39
38
  #include <node/context.h>
40
39
  #include <node/miner.h>
41
40
  #include <node/ui_interface.h>
42
- #include <policy/feerate.h>
43
- #include <policy/fees.h>
44
41
  #include <policy/policy.h>
45
42
  #include <policy/settings.h>
46
43
  #include <protocol.h>
@@ -62,13 +59,13 @@
62
59
  #include <util/check.h>
63
60
  #include <util/moneystr.h>
64
61
  #include <util/strencodings.h>
65
- #include <util/string.h>
66
62
  #include <util/syscall_sandbox.h>
67
63
  #include <util/system.h>
68
64
  #include <util/thread.h>
69
65
  #include <util/threadnames.h>
70
66
  #include <util/translation.h>
71
67
  #include <validation.h>
68
+
72
69
  #include <validationinterface.h>
73
70
  #include <walletinitinterface.h>
74
71
 
@@ -102,17 +99,14 @@ using node::CacheSizes;
102
99
  using node::CalculateCacheSizes;
103
100
  using node::ChainstateLoadVerifyError;
104
101
  using node::ChainstateLoadingError;
105
- using node::CleanupBlockRevFiles;
106
102
  using node::DEFAULT_PRINTPRIORITY;
107
103
  using node::DEFAULT_STOPAFTERBLOCKIMPORT;
108
104
  using node::LoadChainstate;
109
105
  using node::NodeContext;
110
106
  using node::ThreadImport;
111
107
  using node::VerifyLoadedChainstate;
112
- using node::fHavePruned;
113
- using node::fPruneMode;
114
108
  using node::fReindex;
115
- using node::nPruneTarget;
109
+ using interfaces::WalletLoader;
116
110
 
117
111
  static const bool DEFAULT_PROXYRANDOMIZE = true;
118
112
  static const bool DEFAULT_REST_ENABLE = false;
@@ -131,7 +125,9 @@ static const char* DEFAULT_ASMAP_FILENAME="ip_asn.map";
131
125
  /**
132
126
  * The PID file facilities.
133
127
  */
134
- static const char* BITCOIN_PID_FILENAME = "bitcoind.pid";
128
+ static const char* BITCOIN_PID_FILENAME = "peercoind.pid";
129
+
130
+ static std::shared_ptr<CWallet> walletTmp;
135
131
 
136
132
  static fs::path GetPidFile(const ArgsManager& args)
137
133
  {
@@ -245,8 +241,6 @@ void Shutdown(NodeContext& node)
245
241
  DumpMempool(*node.mempool);
246
242
  }
247
243
 
248
- // Drop transactions we were still watching, and record fee estimations.
249
- if (node.fee_estimator) node.fee_estimator->Flush();
250
244
 
251
245
  // FlushStateToDisk generates a ChainStateFlushed callback, which we should avoid missing
252
246
  if (node.chainman) {
@@ -306,7 +300,6 @@ void Shutdown(NodeContext& node)
306
300
  GetMainSignals().UnregisterBackgroundSignalScheduler();
307
301
  init::UnsetGlobals();
308
302
  node.mempool.reset();
309
- node.fee_estimator.reset();
310
303
  node.chainman.reset();
311
304
  node.scheduler.reset();
312
305
 
@@ -420,9 +413,6 @@ void SetupServerArgs(ArgsManager& argsman)
420
413
  -GetNumCores(), MAX_SCRIPTCHECK_THREADS, DEFAULT_SCRIPTCHECK_THREADS), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
421
414
  argsman.AddArg("-persistmempool", strprintf("Whether to save the mempool on shutdown and load on restart (default: %u)", DEFAULT_PERSIST_MEMPOOL), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
422
415
  argsman.AddArg("-pid=<file>", strprintf("Specify pid file. Relative paths will be prefixed by a net-specific datadir location. (default: %s)", BITCOIN_PID_FILENAME), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
423
- argsman.AddArg("-prune=<n>", strprintf("Reduce storage requirements by enabling pruning (deleting) of old blocks. This allows the pruneblockchain RPC to be called to delete specific blocks, and enables automatic pruning of old blocks if a target size in MiB is provided. This mode is incompatible with -txindex and -coinstatsindex. "
424
- "Warning: Reverting this setting requires re-downloading the entire blockchain. "
425
- "(default: 0 = disable pruning blocks, 1 = allow manual pruning via RPC, >=%u = automatically prune block files to stay under the specified target size in MiB)", MIN_DISK_SPACE_FOR_BLOCK_FILES / 1024 / 1024), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
426
416
  argsman.AddArg("-reindex", "Rebuild chain state and block index from the blk*.dat files on disk", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
427
417
  argsman.AddArg("-reindex-chainstate", "Rebuild chain state from the currently indexed blocks. When in pruning mode or if blocks on disk might be corrupted, use full -reindex instead.", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
428
418
  argsman.AddArg("-settings=<file>", strprintf("Specify path to dynamic settings data file. Can be disabled with -nosettings. File is written at runtime and not meant to be edited by users (use %s instead for custom settings). Relative paths will be prefixed by datadir location. (default: %s)", BITCOIN_CONF_FILENAME, BITCOIN_SETTINGS_FILENAME), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
@@ -549,19 +539,15 @@ void SetupServerArgs(ArgsManager& argsman)
549
539
  SetupChainParamsBaseOptions(argsman);
550
540
 
551
541
  argsman.AddArg("-acceptnonstdtxn", strprintf("Relay and mine \"non-standard\" transactions (%sdefault: %u)", "testnet/regtest only; ", !testnetChainParams->RequireStandard()), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::NODE_RELAY);
552
- argsman.AddArg("-incrementalrelayfee=<amt>", strprintf("Fee rate (in %s/kvB) used to define cost of relay, used for mempool limiting and BIP 125 replacement. (default: %s)", CURRENCY_UNIT, FormatMoney(DEFAULT_INCREMENTAL_RELAY_FEE)), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::NODE_RELAY);
553
- argsman.AddArg("-dustrelayfee=<amt>", strprintf("Fee rate (in %s/kvB) used to define dust, the value of an output such that it will cost more than its value in fees at this fee rate to spend it. (default: %s)", CURRENCY_UNIT, FormatMoney(DUST_RELAY_TX_FEE)), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::NODE_RELAY);
554
542
  argsman.AddArg("-bytespersigop", strprintf("Equivalent bytes per sigop in transactions for relay and mining (default: %u)", DEFAULT_BYTES_PER_SIGOP), ArgsManager::ALLOW_ANY, OptionsCategory::NODE_RELAY);
555
543
  argsman.AddArg("-datacarrier", strprintf("Relay and mine data carrier transactions (default: %u)", DEFAULT_ACCEPT_DATACARRIER), ArgsManager::ALLOW_ANY, OptionsCategory::NODE_RELAY);
556
544
  argsman.AddArg("-datacarriersize", strprintf("Maximum size of data in data carrier transactions we relay and mine (default: %u)", MAX_OP_RETURN_RELAY), ArgsManager::ALLOW_ANY, OptionsCategory::NODE_RELAY);
557
- argsman.AddArg("-minrelaytxfee=<amt>", strprintf("Fees (in %s/kvB) smaller than this are considered zero fee for relaying, mining and transaction creation (default: %s)",
558
- CURRENCY_UNIT, FormatMoney(DEFAULT_MIN_RELAY_TX_FEE)), ArgsManager::ALLOW_ANY, OptionsCategory::NODE_RELAY);
545
+
559
546
  argsman.AddArg("-whitelistforcerelay", strprintf("Add 'forcerelay' permission to whitelisted inbound peers with default permissions. This will relay transactions even if the transactions were already in the mempool. (default: %d)", DEFAULT_WHITELISTFORCERELAY), ArgsManager::ALLOW_ANY, OptionsCategory::NODE_RELAY);
560
547
  argsman.AddArg("-whitelistrelay", strprintf("Add 'relay' permission to whitelisted inbound peers with default permissions. This will accept relayed transactions even when not relaying transactions (default: %d)", DEFAULT_WHITELISTRELAY), ArgsManager::ALLOW_ANY, OptionsCategory::NODE_RELAY);
561
548
 
562
549
 
563
550
  argsman.AddArg("-blockmaxweight=<n>", strprintf("Set maximum BIP141 block weight (default: %d)", DEFAULT_BLOCK_MAX_WEIGHT), ArgsManager::ALLOW_ANY, OptionsCategory::BLOCK_CREATION);
564
- argsman.AddArg("-blockmintxfee=<amt>", strprintf("Set lowest fee rate (in %s/kvB) for transactions to be included in block creation. (default: %s)", CURRENCY_UNIT, FormatMoney(DEFAULT_BLOCK_MIN_TX_FEE)), ArgsManager::ALLOW_ANY, OptionsCategory::BLOCK_CREATION);
565
551
  argsman.AddArg("-blockversion=<n>", "Override block version to test forking scenarios", ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::BLOCK_CREATION);
566
552
 
567
553
  argsman.AddArg("-rest", strprintf("Accept public REST requests (default: %u)", DEFAULT_REST_ENABLE), ArgsManager::ALLOW_ANY, OptionsCategory::RPC);
@@ -579,6 +565,7 @@ void SetupServerArgs(ArgsManager& argsman)
579
565
  argsman.AddArg("-rpcwhitelistdefault", "Sets default behavior for rpc whitelisting. Unless rpcwhitelistdefault is set to 0, if any -rpcwhitelist is set, the rpc server acts as if all rpc users are subject to empty-unless-otherwise-specified whitelists. If rpcwhitelistdefault is set to 1 and no -rpcwhitelist is set, rpc server acts as if all rpc users are subject to empty whitelists.", ArgsManager::ALLOW_ANY, OptionsCategory::RPC);
580
566
  argsman.AddArg("-rpcworkqueue=<n>", strprintf("Set the depth of the work queue to service RPC calls (default: %d)", DEFAULT_HTTP_WORKQUEUE), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::RPC);
581
567
  argsman.AddArg("-server", "Accept command line and JSON-RPC commands", ArgsManager::ALLOW_ANY, OptionsCategory::RPC);
568
+ gArgs.AddArg("-nominting", "Disable minting of POS blocks", ArgsManager::ALLOW_ANY, OptionsCategory::BLOCK_CREATION);
582
569
 
583
570
  #if HAVE_DECL_FORK
584
571
  argsman.AddArg("-daemon", strprintf("Run in the background as a daemon and accept commands (default: %d)", DEFAULT_DAEMON), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
@@ -592,6 +579,15 @@ void SetupServerArgs(ArgsManager& argsman)
592
579
  argsman.AddArg("-sandbox=<mode>", "Use the experimental syscall sandbox in the specified mode (-sandbox=log-and-abort or -sandbox=abort). Allow only expected syscalls to be used by bitcoind. Note that this is an experimental new feature that may cause bitcoind to exit or crash unexpectedly: use with caution. In the \"log-and-abort\" mode the invocation of an unexpected syscall results in a debug handler being invoked which will log the incident and terminate the program (without executing the unexpected syscall). In the \"abort\" mode the invocation of an unexpected syscall results in the entire process being killed immediately by the kernel without executing the unexpected syscall.", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
593
580
  #endif // USE_SYSCALL_SANDBOX
594
581
 
582
+ // peercoin parameters
583
+ gArgs.AddArg("-printstakemodifier", "Print stakemodifier selection parameters if debug is enabled", ArgsManager::ALLOW_ANY, OptionsCategory::DEBUG_TEST);
584
+ gArgs.AddArg("-printcoinstake", "Print coinstake if debug is enabled", ArgsManager::ALLOW_ANY, OptionsCategory::DEBUG_TEST);
585
+ gArgs.AddArg("-printcoinage", "Print coinage if debug is enabled", ArgsManager::ALLOW_ANY, OptionsCategory::DEBUG_TEST);
586
+ gArgs.AddArg("-printcreation", "Print coin creation if debug is enabled", ArgsManager::ALLOW_ANY, OptionsCategory::DEBUG_TEST);
587
+
588
+ gArgs.AddArg("-reservebalance=<amt>", "Reserve this many coins", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
589
+ gArgs.AddArg("-minting", "Enable minting (default: true)", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
590
+
595
591
  // Add the hidden options
596
592
  argsman.AddHiddenArgs(hidden_args);
597
593
  }
@@ -853,14 +849,6 @@ bool AppInitParameterInteraction(const ArgsManager& args)
853
849
  nLocalServices = ServiceFlags(nLocalServices | NODE_COMPACT_FILTERS);
854
850
  }
855
851
 
856
- // if using block pruning, then disallow txindex and coinstatsindex
857
- if (args.GetIntArg("-prune", 0)) {
858
- if (args.GetBoolArg("-txindex", DEFAULT_TXINDEX))
859
- return InitError(_("Prune mode is incompatible with -txindex."));
860
- if (args.GetBoolArg("-coinstatsindex", DEFAULT_COINSTATSINDEX))
861
- return InitError(_("Prune mode is incompatible with -coinstatsindex."));
862
- }
863
-
864
852
  // If -forcednsseed is set to true, ensure -dnsseed has not been set to false
865
853
  if (args.GetBoolArg("-forcednsseed", DEFAULT_FORCEDNSSEED) && !args.GetBoolArg("-dnsseed", DEFAULT_DNSSEED)){
866
854
  return InitError(_("Cannot set -forcednsseed to true when setting -dnsseed to false."));
@@ -930,33 +918,6 @@ bool AppInitParameterInteraction(const ArgsManager& args)
930
918
  int64_t nMempoolSizeMin = args.GetIntArg("-limitdescendantsize", DEFAULT_DESCENDANT_SIZE_LIMIT) * 1000 * 40;
931
919
  if (nMempoolSizeMax < 0 || nMempoolSizeMax < nMempoolSizeMin)
932
920
  return InitError(strprintf(_("-maxmempool must be at least %d MB"), std::ceil(nMempoolSizeMin / 1000000.0)));
933
- // incremental relay fee sets the minimum feerate increase necessary for BIP 125 replacement in the mempool
934
- // and the amount the mempool min fee increases above the feerate of txs evicted due to mempool limiting.
935
- if (args.IsArgSet("-incrementalrelayfee")) {
936
- if (std::optional<CAmount> inc_relay_fee = ParseMoney(args.GetArg("-incrementalrelayfee", ""))) {
937
- ::incrementalRelayFee = CFeeRate{inc_relay_fee.value()};
938
- } else {
939
- return InitError(AmountErrMsg("incrementalrelayfee", args.GetArg("-incrementalrelayfee", "")));
940
- }
941
- }
942
-
943
- // block pruning; get the amount of disk space (in MiB) to allot for block & undo files
944
- int64_t nPruneArg = args.GetIntArg("-prune", 0);
945
- if (nPruneArg < 0) {
946
- return InitError(_("Prune cannot be configured with a negative value."));
947
- }
948
- nPruneTarget = (uint64_t) nPruneArg * 1024 * 1024;
949
- if (nPruneArg == 1) { // manual pruning: -prune=1
950
- LogPrintf("Block pruning enabled. Use RPC call pruneblockchain(height) to manually prune block and undo files.\n");
951
- nPruneTarget = std::numeric_limits<uint64_t>::max();
952
- fPruneMode = true;
953
- } else if (nPruneTarget) {
954
- if (nPruneTarget < MIN_DISK_SPACE_FOR_BLOCK_FILES) {
955
- return InitError(strprintf(_("Prune configured below the minimum of %d MiB. Please use a higher number."), MIN_DISK_SPACE_FOR_BLOCK_FILES / 1024 / 1024));
956
- }
957
- LogPrintf("Prune configured to target %u MiB on disk for block and undo files.\n", nPruneTarget / 1024 / 1024);
958
- fPruneMode = true;
959
- }
960
921
 
961
922
  nConnectTimeout = args.GetIntArg("-timeout", DEFAULT_CONNECT_TIMEOUT);
962
923
  if (nConnectTimeout <= 0) {
@@ -967,38 +928,6 @@ bool AppInitParameterInteraction(const ArgsManager& args)
967
928
  if (peer_connect_timeout <= 0) {
968
929
  return InitError(Untranslated("peertimeout cannot be configured with a negative value."));
969
930
  }
970
-
971
- if (args.IsArgSet("-minrelaytxfee")) {
972
- if (std::optional<CAmount> min_relay_fee = ParseMoney(args.GetArg("-minrelaytxfee", ""))) {
973
- // High fee check is done afterward in CWallet::Create()
974
- ::minRelayTxFee = CFeeRate{min_relay_fee.value()};
975
- } else {
976
- return InitError(AmountErrMsg("minrelaytxfee", args.GetArg("-minrelaytxfee", "")));
977
- }
978
- } else if (incrementalRelayFee > ::minRelayTxFee) {
979
- // Allow only setting incrementalRelayFee to control both
980
- ::minRelayTxFee = incrementalRelayFee;
981
- LogPrintf("Increasing minrelaytxfee to %s to match incrementalrelayfee\n",::minRelayTxFee.ToString());
982
- }
983
-
984
- // Sanity check argument for min fee for including tx in block
985
- // TODO: Harmonize which arguments need sanity checking and where that happens
986
- if (args.IsArgSet("-blockmintxfee")) {
987
- if (!ParseMoney(args.GetArg("-blockmintxfee", ""))) {
988
- return InitError(AmountErrMsg("blockmintxfee", args.GetArg("-blockmintxfee", "")));
989
- }
990
- }
991
-
992
- // Feerate used to define dust. Shouldn't be changed lightly as old
993
- // implementations may inadvertently create non-standard transactions
994
- if (args.IsArgSet("-dustrelayfee")) {
995
- if (std::optional<CAmount> parsed = ParseMoney(args.GetArg("-dustrelayfee", ""))) {
996
- dustRelayFee = CFeeRate{parsed.value()};
997
- } else {
998
- return InitError(AmountErrMsg("dustrelayfee", args.GetArg("-dustrelayfee", "")));
999
- }
1000
- }
1001
-
1002
931
  fRequireStandard = !args.GetBoolArg("-acceptnonstdtxn", !chainparams.RequireStandard());
1003
932
  if (!chainparams.IsTestChain() && !fRequireStandard) {
1004
933
  return InitError(strprintf(Untranslated("acceptnonstdtxn is not currently supported for %s chain"), chainparams.NetworkIDString()));
@@ -1024,7 +953,6 @@ bool AppInitParameterInteraction(const ArgsManager& args)
1024
953
  return InitError(Untranslated("Unknown rpcserialversion requested."));
1025
954
 
1026
955
  nMaxTipAge = args.GetIntArg("-maxtipage", DEFAULT_MAX_TIP_AGE);
1027
-
1028
956
  if (args.IsArgSet("-proxy") && args.GetArg("-proxy", "").empty()) {
1029
957
  return InitError(_("No proxy server specified. Use -proxy=<ip> or -proxy=<ip:port>."));
1030
958
  }
@@ -1065,7 +993,7 @@ bool AppInitParameterInteraction(const ArgsManager& args)
1065
993
 
1066
994
  static bool LockDataDirectory(bool probeOnly)
1067
995
  {
1068
- // Make sure only a single Bitcoin process is using the data directory.
996
+ // Make sure only a single Peercoin process is using the data directory.
1069
997
  fs::path datadir = gArgs.GetDataDirNet();
1070
998
  if (!DirIsWritable(datadir)) {
1071
999
  return InitError(strprintf(_("Cannot write to data directory '%s'; check permissions."), fs::PathToString(datadir)));
@@ -1082,6 +1010,8 @@ bool AppInitSanityChecks()
1082
1010
 
1083
1011
  init::SetGlobals();
1084
1012
 
1013
+ // peercoin: init hash seed
1014
+ peercoinRandseed = GetRand(1 << 30);
1085
1015
  if (!init::SanityChecks()) {
1086
1016
  return InitError(strprintf(_("Initialization sanity check failed. %s is shutting down."), PACKAGE_NAME));
1087
1017
  }
@@ -1135,9 +1065,9 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
1135
1065
  // Warn about relative -datadir path.
1136
1066
  if (args.IsArgSet("-datadir") && !args.GetPathArg("-datadir").is_absolute()) {
1137
1067
  LogPrintf("Warning: relative datadir option '%s' specified, which will be interpreted relative to the " /* Continued */
1138
- "current working directory '%s'. This is fragile, because if bitcoin is started in the future "
1068
+ "current working directory '%s'. This is fragile, because if peercoin is started in the future "
1139
1069
  "from a different location, it will be unable to locate the current data files. There could "
1140
- "also be data loss if bitcoin is started while in a temporary directory.\n",
1070
+ "also be data loss if peercoin is started while in a temporary directory.\n",
1141
1071
  args.GetArg("-datadir", ""), fs::PathToString(fs::current_path()));
1142
1072
  }
1143
1073
 
@@ -1262,14 +1192,9 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
1262
1192
  assert(!node.connman);
1263
1193
  node.connman = std::make_unique<CConnman>(GetRand(std::numeric_limits<uint64_t>::max()), GetRand(std::numeric_limits<uint64_t>::max()), *node.addrman, args.GetBoolArg("-networkactive", true));
1264
1194
 
1265
- assert(!node.fee_estimator);
1266
- // Don't initialize fee estimation with old data if we don't relay transactions,
1267
- // as they would never get updated.
1268
- if (!ignores_incoming_txs) node.fee_estimator = std::make_unique<CBlockPolicyEstimator>();
1269
-
1270
1195
  assert(!node.mempool);
1271
1196
  int check_ratio = std::min<int>(std::max<int>(args.GetIntArg("-checkmempool", chainparams.DefaultConsistencyChecks() ? 1 : 0), 0), 1000000);
1272
- node.mempool = std::make_unique<CTxMemPool>(node.fee_estimator.get(), check_ratio);
1197
+ node.mempool = std::make_unique<CTxMemPool>(check_ratio);
1273
1198
 
1274
1199
  assert(!node.chainman);
1275
1200
  node.chainman = std::make_unique<ChainstateManager>();
@@ -1397,9 +1322,7 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
1397
1322
  int64_t nMempoolSizeMax = args.GetIntArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000;
1398
1323
  LogPrintf("Cache configuration:\n");
1399
1324
  LogPrintf("* Using %.1f MiB for block index database\n", cache_sizes.block_tree_db * (1.0 / 1024 / 1024));
1400
- if (args.GetBoolArg("-txindex", DEFAULT_TXINDEX)) {
1401
- LogPrintf("* Using %.1f MiB for transaction index database\n", cache_sizes.tx_index * (1.0 / 1024 / 1024));
1402
- }
1325
+ LogPrintf("* Using %.1f MiB for transaction index database\n", cache_sizes.tx_index * (1.0 / 1024 / 1024));
1403
1326
  for (BlockFilterType filter_type : g_enabled_filter_types) {
1404
1327
  LogPrintf("* Using %.1f MiB for %s block filter index database\n",
1405
1328
  cache_sizes.filter_index * (1.0 / 1024 / 1024), BlockFilterTypeName(filter_type));
@@ -1419,7 +1342,6 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
1419
1342
  maybe_load_error = LoadChainstate(fReset,
1420
1343
  chainman,
1421
1344
  Assert(node.mempool.get()),
1422
- fPruneMode,
1423
1345
  chainparams.GetConsensus(),
1424
1346
  fReindexChainState,
1425
1347
  cache_sizes.block_tree_db,
@@ -1446,9 +1368,6 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
1446
1368
  // If the loaded chain has a wrong genesis, bail out immediately
1447
1369
  // (we're likely using a testnet datadir, or the other way around).
1448
1370
  return InitError(_("Incorrect or no genesis block found. Wrong datadir for network?"));
1449
- case ChainstateLoadingError::ERROR_PRUNED_NEEDS_REINDEX:
1450
- strLoadError = _("You need to rebuild the database using -reindex to go back to unpruned mode. This will redownload the entire blockchain");
1451
- break;
1452
1371
  case ChainstateLoadingError::ERROR_LOAD_GENESIS_BLOCK_FAILED:
1453
1372
  strLoadError = _("Error initializing block database");
1454
1373
  break;
@@ -1476,10 +1395,6 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
1476
1395
  try {
1477
1396
  uiInterface.InitMessage(_("Verifying blocks…").translated);
1478
1397
  auto check_blocks = args.GetIntArg("-checkblocks", DEFAULT_CHECKBLOCKS);
1479
- if (fHavePruned && check_blocks > MIN_BLOCKS_TO_KEEP) {
1480
- LogPrintf("Prune: pruned datadir may not have more than %d blocks; only checking available blocks\n",
1481
- MIN_BLOCKS_TO_KEEP);
1482
- }
1483
1398
  maybe_verify_error = VerifyLoadedChainstate(chainman,
1484
1399
  fReset,
1485
1400
  fReindexChainState,
@@ -1540,15 +1455,13 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
1540
1455
  }
1541
1456
 
1542
1457
  // ********************************************************* Step 8: start indexers
1543
- if (args.GetBoolArg("-txindex", DEFAULT_TXINDEX)) {
1544
1458
  if (const auto error{CheckLegacyTxindex(*Assert(chainman.m_blockman.m_block_tree_db))}) {
1545
1459
  return InitError(*error);
1546
1460
  }
1547
1461
 
1548
- g_txindex = std::make_unique<TxIndex>(cache_sizes.tx_index, false, fReindex);
1549
- if (!g_txindex->Start(chainman.ActiveChainstate())) {
1550
- return false;
1551
- }
1462
+ g_txindex = std::make_unique<TxIndex>(cache_sizes.tx_index, false, fReindex);
1463
+ if (!g_txindex->Start(chainman.ActiveChainstate())) {
1464
+ return false;
1552
1465
  }
1553
1466
 
1554
1467
  for (const auto& filter_type : g_enabled_filter_types) {
@@ -1574,19 +1487,9 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
1574
1487
 
1575
1488
  // ********************************************************* Step 10: data directory maintenance
1576
1489
 
1577
- // if pruning, unset the service bit and perform the initial blockstore prune
1578
- // after any wallet rescanning has taken place.
1579
- if (fPruneMode) {
1580
- LogPrintf("Unsetting NODE_NETWORK on prune mode\n");
1581
- nLocalServices = ServiceFlags(nLocalServices & ~NODE_NETWORK);
1582
- if (!fReindex) {
1583
- LOCK(cs_main);
1584
- for (CChainState* chainstate : chainman.GetAll()) {
1585
- uiInterface.InitMessage(_("Pruning blockstore…").translated);
1586
- chainstate->PruneAndFlush();
1587
- }
1588
- }
1589
- }
1490
+ // Note that setting NODE_WITNESS is never required: the only downside from not
1491
+ // doing so is that after activation, no upgraded nodes will fetch from you.
1492
+ nLocalServices = ServiceFlags(nLocalServices | NODE_WITNESS);
1590
1493
 
1591
1494
  // ********************************************************* Step 11: import blocks
1592
1495
 
@@ -1829,6 +1732,15 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
1829
1732
 
1830
1733
  #if HAVE_SYSTEM
1831
1734
  StartupNotify(args);
1735
+ #endif
1736
+ #ifdef ENABLE_WALLET
1737
+ {
1738
+ // ppctodo: deal with multiple wallets
1739
+ if (node.wallet_loader->getWallets().size() && gArgs.GetBoolArg("-stakegen", true)) {
1740
+ walletTmp = std::shared_ptr<CWallet>(node.wallet_loader->getWallets()[0]->wallet());
1741
+ MintStake(walletTmp, node);
1742
+ }
1743
+ }
1832
1744
  #endif
1833
1745
 
1834
1746
  return true;
src/interfaces/chain.h CHANGED
@@ -5,6 +5,7 @@
5
5
  #ifndef BITCOIN_INTERFACES_CHAIN_H
6
6
  #define BITCOIN_INTERFACES_CHAIN_H
7
7
 
8
+ #include <node/chainstate.h>
8
9
  #include <primitives/transaction.h> // For CTransactionRef
9
10
  #include <util/settings.h> // For util::SettingsValue
10
11
 
@@ -18,16 +19,13 @@
18
19
 
19
20
  class ArgsManager;
20
21
  class CBlock;
21
- class CFeeRate;
22
22
  class CRPCCommand;
23
23
  class CScheduler;
24
24
  class Coin;
25
25
  class uint256;
26
26
  enum class MemPoolRemovalReason;
27
- enum class RBFTransactionState;
28
27
  struct bilingual_str;
29
28
  struct CBlockLocator;
30
- struct FeeCalculation;
31
29
  namespace node {
32
30
  struct NodeContext;
33
31
  } // namespace node
@@ -96,6 +94,8 @@ class Chain
96
94
  public:
97
95
  virtual ~Chain() {}
98
96
 
97
+ virtual ChainstateManager& chainman() = 0;
98
+
99
99
  //! Get current chain height, not including genesis block (returns 0 if
100
100
  //! chain only contains genesis block, nullopt if chain does not contain
101
101
  //! any blocks)
@@ -104,8 +104,7 @@ public:
104
104
  //! Get block hash. Height must be valid or this function will abort.
105
105
  virtual uint256 getBlockHash(int height) = 0;
106
106
 
107
- //! Check that the block is available on disk (i.e. has not been
108
- //! pruned), and contains transactions.
107
+ //! Check that the block is available on disk, and contains transactions.
109
108
  virtual bool haveBlockOnDisk(int height) = 0;
110
109
 
111
110
  //! Get locator for the current chain tip.
@@ -158,9 +157,6 @@ public:
158
157
  //! the height range from min_height to max_height, inclusive.
159
158
  virtual bool hasBlocks(const uint256& block_hash, int min_height = 0, std::optional<int> max_height = {}) = 0;
160
159
 
161
- //! Check if transaction is RBF opt in.
162
- virtual RBFTransactionState isRBFOptIn(const CTransaction& tx) = 0;
163
-
164
160
  //! Check if transaction is in mempool.
165
161
  virtual bool isInMempool(const uint256& txid) = 0;
166
162
 
@@ -171,7 +167,6 @@ public:
171
167
  //! amount specified by max_tx_fee, and broadcast to all peers if relay is set to true.
172
168
  //! Return false if the transaction could not be added due to the fee or for another reason.
173
169
  virtual bool broadcastTransaction(const CTransactionRef& tx,
174
- const CAmount& max_tx_fee,
175
170
  bool relay,
176
171
  std::string& err_string) = 0;
177
172
 
@@ -186,27 +181,6 @@ public:
186
181
  //! Check if transaction will pass the mempool's chain limits.
187
182
  virtual bool checkChainLimits(const CTransactionRef& tx) = 0;
188
183
 
189
- //! Estimate smart fee.
190
- virtual CFeeRate estimateSmartFee(int num_blocks, bool conservative, FeeCalculation* calc = nullptr) = 0;
191
-
192
- //! Fee estimator max target.
193
- virtual unsigned int estimateMaxBlocks() = 0;
194
-
195
- //! Mempool minimum fee.
196
- virtual CFeeRate mempoolMinFee() = 0;
197
-
198
- //! Relay current minimum fee (from -minrelaytxfee and -incrementalrelayfee settings).
199
- virtual CFeeRate relayMinFee() = 0;
200
-
201
- //! Relay incremental fee setting (-incrementalrelayfee), reflecting cost of relay.
202
- virtual CFeeRate relayIncrementalFee() = 0;
203
-
204
- //! Relay dust fee setting (-dustrelayfee), reflecting lowest rate it's economical to spend.
205
- virtual CFeeRate relayDustFee() = 0;
206
-
207
- //! Check if any block has been pruned.
208
- virtual bool havePruned() = 0;
209
-
210
184
  //! Check if the node is ready to broadcast transactions.
211
185
  virtual bool isReadyToBroadcast() = 0;
212
186
 
src/interfaces/init.h CHANGED
@@ -6,6 +6,9 @@
6
6
  #define BITCOIN_INTERFACES_INIT_H
7
7
 
8
8
  #include <memory>
9
+ #include <interfaces/wallet.h>
10
+
11
+ using interfaces::WalletLoader;
9
12
 
10
13
  namespace node {
11
14
  struct NodeContext;
@@ -16,7 +19,7 @@ class Chain;
16
19
  class Echo;
17
20
  class Ipc;
18
21
  class Node;
19
- class WalletLoader;
22
+ //class WalletLoader;
20
23
 
21
24
  //! Initial interface created when a process is first started, and used to give
22
25
  //! and get access to other interfaces (Node, Chain, Wallet, etc).
src/interfaces/node.h CHANGED
@@ -6,11 +6,13 @@
6
6
  #define BITCOIN_INTERFACES_NODE_H
7
7
 
8
8
  #include <consensus/amount.h>
9
+ #include <node/chainstate.h>
9
10
  #include <net.h> // For NodeId
10
11
  #include <net_types.h> // For banmap_t
11
12
  #include <netaddress.h> // For Network
12
13
  #include <netbase.h> // For ConnectionDirection
13
14
  #include <support/allocators/secure.h> // For SecureString
15
+ #include <util/ui_change_type.h>
14
16
  #include <util/translation.h>
15
17
 
16
18
  #include <functional>
@@ -22,7 +24,6 @@
22
24
  #include <vector>
23
25
 
24
26
  class BanMan;
25
- class CFeeRate;
26
27
  class CNodeStats;
27
28
  class Coin;
28
29
  class RPCTimerInterface;
@@ -70,6 +71,8 @@ class Node
70
71
  public:
71
72
  virtual ~Node() {}
72
73
 
74
+ virtual ChainstateManager& chainman() = 0;
75
+
73
76
  //! Init logging.
74
77
  virtual void initLogging() = 0;
75
78
 
@@ -170,9 +173,6 @@ public:
170
173
  //! Get network active.
171
174
  virtual bool getNetworkActive() = 0;
172
175
 
173
- //! Get dust relay fee.
174
- virtual CFeeRate getDustRelayFee() = 0;
175
-
176
176
  //! Execute rpc command.
177
177
  virtual UniValue executeRpc(const std::string& command, const UniValue& params, const std::string& uri) = 0;
178
178
 
@@ -189,7 +189,7 @@ public:
189
189
  virtual bool getUnspentOutput(const COutPoint& output, Coin& coin) = 0;
190
190
 
191
191
  //! Broadcast transaction.
192
- virtual TransactionError broadcastTransaction(CTransactionRef tx, CAmount max_tx_fee, std::string& err_string) = 0;
192
+ virtual TransactionError broadcastTransaction(CTransactionRef tx, std::string& err_string) = 0;
193
193
 
194
194
  //! Get wallet loader.
195
195
  virtual WalletLoader& walletLoader() = 0;
@@ -227,7 +227,7 @@ public:
227
227
  virtual std::unique_ptr<Handler> handleNotifyNetworkActiveChanged(NotifyNetworkActiveChangedFn fn) = 0;
228
228
 
229
229
  //! Register handler for notify alert messages.
230
- using NotifyAlertChangedFn = std::function<void()>;
230
+ using NotifyAlertChangedFn = std::function<void(const uint256 &hash, ChangeType status)>;
231
231
  virtual std::unique_ptr<Handler> handleNotifyAlertChanged(NotifyAlertChangedFn fn) = 0;
232
232
 
233
233
  //! Register handler for ban list messages.
src/interfaces/wallet.h CHANGED
@@ -24,7 +24,6 @@
24
24
  #include <utility>
25
25
  #include <vector>
26
26
 
27
- class CFeeRate;
28
27
  class CKey;
29
28
  enum class FeeReason;
30
29
  enum class OutputType;
@@ -156,26 +155,6 @@ public:
156
155
  //! Abandon transaction.
157
156
  virtual bool abandonTransaction(const uint256& txid) = 0;
158
157
 
159
- //! Return whether transaction can be bumped.
160
- virtual bool transactionCanBeBumped(const uint256& txid) = 0;
161
-
162
- //! Create bump transaction.
163
- virtual bool createBumpTransaction(const uint256& txid,
164
- const wallet::CCoinControl& coin_control,
165
- std::vector<bilingual_str>& errors,
166
- CAmount& old_fee,
167
- CAmount& new_fee,
168
- CMutableTransaction& mtx) = 0;
169
-
170
- //! Sign bump transaction.
171
- virtual bool signBumpTransaction(CMutableTransaction& mtx) = 0;
172
-
173
- //! Commit bump transaction.
174
- virtual bool commitBumpTransaction(const uint256& txid,
175
- CMutableTransaction&& mtx,
176
- std::vector<bilingual_str>& errors,
177
- uint256& bumped_txid) = 0;
178
-
179
158
  //! Get a transaction.
180
159
  virtual CTransactionRef getTx(const uint256& txid) = 0;
181
160
 
@@ -237,7 +216,7 @@ public:
237
216
 
238
217
  //! Return wallet transaction output information.
239
218
  virtual std::vector<WalletTxOut> getCoins(const std::vector<COutPoint>& outputs) = 0;
240
-
219
+ /*
241
220
  //! Get required fee.
242
221
  virtual CAmount getRequiredFee(unsigned int tx_bytes) = 0;
243
222
 
@@ -249,7 +228,7 @@ public:
249
228
 
250
229
  //! Get tx confirm target.
251
230
  virtual unsigned int getConfirmTarget() = 0;
252
-
231
+ */
253
232
  // Return whether HD enabled.
254
233
  virtual bool hdEnabled() = 0;
255
234
 
@@ -268,9 +247,6 @@ public:
268
247
  // Get default address type.
269
248
  virtual OutputType getDefaultAddressType() = 0;
270
249
 
271
- //! Get max tx fee.
272
- virtual CAmount getDefaultMaxTxFee() = 0;
273
-
274
250
  // Remove wallet.
275
251
  virtual void remove() = 0;
276
252
 
@@ -311,6 +287,9 @@ public:
311
287
 
312
288
  //! Return pointer to internal wallet class, useful for testing.
313
289
  virtual wallet::CWallet* wallet() { return nullptr; }
290
+ // peercoin
291
+ virtual void relockWalletAfterDuration(int nDuration) = 0;
292
+ virtual std::shared_ptr<wallet::CWallet> getWallet() = 0;
314
293
  };
315
294
 
316
295
  //! Wallet chain client that in addition to having chain client methods for
@@ -365,6 +344,7 @@ struct WalletAddress
365
344
  struct WalletBalances
366
345
  {
367
346
  CAmount balance = 0;
347
+ CAmount stake = 0;
368
348
  CAmount unconfirmed_balance = 0;
369
349
  CAmount immature_balance = 0;
370
350
  bool have_watch_only = false;
@@ -374,7 +354,7 @@ struct WalletBalances
374
354
 
375
355
  bool balanceChanged(const WalletBalances& prev) const
376
356
  {
377
- return balance != prev.balance || unconfirmed_balance != prev.unconfirmed_balance ||
357
+ return balance != prev.balance || stake != prev.stake || unconfirmed_balance != prev.unconfirmed_balance ||
378
358
  immature_balance != prev.immature_balance || watch_only_balance != prev.watch_only_balance ||
379
359
  unconfirmed_watch_only_balance != prev.unconfirmed_watch_only_balance ||
380
360
  immature_watch_only_balance != prev.immature_watch_only_balance;
@@ -395,6 +375,7 @@ struct WalletTx
395
375
  int64_t time;
396
376
  std::map<std::string, std::string> value_map;
397
377
  bool is_coinbase;
378
+ bool is_coinstake;
398
379
  };
399
380
 
400
381
  //! Updated transaction status.
@@ -408,6 +389,7 @@ struct WalletTxStatus
408
389
  bool is_trusted;
409
390
  bool is_abandoned;
410
391
  bool is_coinbase;
392
+ bool is_coinstake;
411
393
  bool is_in_main_chain;
412
394
  };
413
395
 
src/kernel.cpp ADDED
@@ -0,0 +1,725 @@
1
+ // Copyright (c) 2012-2023 The Peercoin developers
2
+ // Distributed under the MIT software license, see the accompanying
3
+ // file COPYING or http://www.opensource.org/licenses/mit-license.php.
4
+
5
+ #include <kernel.h>
6
+ #include <chainparams.h>
7
+ #include <validation.h>
8
+ #include <streams.h>
9
+ #include <timedata.h>
10
+ #include <bignum.h>
11
+ #include <txdb.h>
12
+ #include <consensus/validation.h>
13
+ #include <validation.h>
14
+ #include <random.h>
15
+ #include <script/interpreter.h>
16
+
17
+ #include <index/txindex.h>
18
+
19
+ #include <boost/assign/list_of.hpp>
20
+
21
+ using namespace std;
22
+
23
+ // Protocol switch time of v0.3 kernel protocol
24
+ unsigned int nProtocolV03SwitchTime = 1363800000;
25
+ unsigned int nProtocolV03TestSwitchTime = 1359781000;
26
+ // Protocol switch time of v0.4 kernel protocol
27
+ unsigned int nProtocolV04SwitchTime = 1399300000;
28
+ unsigned int nProtocolV04TestSwitchTime = 1395700000;
29
+ // Protocol switch time of v0.5 kernel protocol
30
+ unsigned int nProtocolV05SwitchTime = 1461700000;
31
+ unsigned int nProtocolV05TestSwitchTime = 1447700000;
32
+ // Protocol switch time of v0.6 kernel protocol
33
+ // supermajority hardfork: actual fork will happen later than switch time
34
+ const unsigned int nProtocolV06SwitchTime = 1513050000; // Tue 12 Dec 03:40:00 UTC 2017
35
+ const unsigned int nProtocolV06TestSwitchTime = 1508198400; // Tue 17 Oct 00:00:00 UTC 2017
36
+ // Protocol switch time for 0.7 kernel protocol
37
+ const unsigned int nProtocolV07SwitchTime = 1552392000; // Tue 12 Mar 12:00:00 UTC 2019
38
+ const unsigned int nProtocolV07TestSwitchTime = 1541505600; // Tue 06 Nov 12:00:00 UTC 2018
39
+ // Switch time for new BIPs from bitcoin 0.16.x
40
+ const uint32_t nBTC16BIPsSwitchTime = 1569931200; // Tue 01 Oct 12:00:00 UTC 2019
41
+ const uint32_t nBTC16BIPsTestSwitchTime = 1554811200; // Tue 09 Apr 12:00:00 UTC 2019
42
+ // Protocol switch time for v0.9 kernel protocol
43
+ const unsigned int nProtocolV09SwitchTime = 1591617600; // Mon 8 Jun 12:00:00 UTC 2020
44
+ const unsigned int nProtocolV09TestSwitchTime = 1581940800; // Mon 17 Feb 12:00:00 UTC 2020
45
+ // Protocol switch time for v10 kernel protocol
46
+ const unsigned int nProtocolV10SwitchTime = 1635768000; // Mon 1 Nov 12:00:00 UTC 2021
47
+ const unsigned int nProtocolV10TestSwitchTime = 1625140800; // Thu 1 Jul 12:00:00 UTC 2021
48
+ // Protocol switch time for v12 kernel protocol
49
+ const unsigned int nProtocolV12SwitchTime = 1681732800; // Mon 17 Apr 12:00:00 UTC 2023
50
+ const unsigned int nProtocolV12TestSwitchTime = 1669636800; // Mon 28 Nov 12:00:00 UTC 2022
51
+
52
+ // Hard checkpoints of stake modifiers to ensure they are deterministic
53
+ static std::map<int, unsigned int> mapStakeModifierCheckpoints =
54
+ boost::assign::map_list_of
55
+ ( 0, 0x0e00670bu )
56
+ ( 19080, 0xad4e4d29u )
57
+ ( 30583, 0xdc7bf136u )
58
+ ( 99999, 0xf555cfd2u )
59
+ (219999, 0x91b7444du )
60
+ (336000, 0x6c3c8048u )
61
+ (371850, 0x9b850bdfu )
62
+ (407813, 0x46fe50b5u )
63
+ (443561, 0x114a6e38u )
64
+ (455470, 0x9b7af181u )
65
+ (479189, 0xe04fb8e0u )
66
+ (504051, 0x459f5a16u )
67
+ (589659, 0xbd02492au )
68
+ ;
69
+
70
+ static std::map<int, unsigned int> mapStakeModifierTestnetCheckpoints =
71
+ boost::assign::map_list_of
72
+ ( 0, 0x0e00670bu )
73
+ ( 19080, 0x3711dc3au )
74
+ ( 30583, 0xb480fadeu )
75
+ ( 99999, 0x9a62eaecu )
76
+ (219999, 0xeafe96c3u )
77
+ (336000, 0x8330dc09u )
78
+ (372751, 0xafb94e2fu )
79
+ (382019, 0x7f5cf5ebu )
80
+ (408500, 0x68cadee2u )
81
+ (412691, 0x93138e67u )
82
+ (441299, 0x03e195cbu )
83
+ (442735, 0xe42d94feu )
84
+ ;
85
+
86
+ // Whether the given coinstake is subject to new v0.3 protocol
87
+ bool IsProtocolV03(unsigned int nTimeCoinStake)
88
+ {
89
+ return (nTimeCoinStake >= (Params().NetworkIDString() != CBaseChainParams::MAIN ? nProtocolV03TestSwitchTime : nProtocolV03SwitchTime));
90
+ }
91
+
92
+ // Whether the given block is subject to new v0.4 protocol
93
+ bool IsProtocolV04(unsigned int nTimeBlock)
94
+ {
95
+ return (nTimeBlock >= (Params().NetworkIDString() != CBaseChainParams::MAIN ? nProtocolV04TestSwitchTime : nProtocolV04SwitchTime));
96
+ }
97
+
98
+ // Whether the given transaction is subject to new v0.5 protocol
99
+ bool IsProtocolV05(unsigned int nTimeTx)
100
+ {
101
+ return (nTimeTx >= (Params().NetworkIDString() != CBaseChainParams::MAIN ? nProtocolV05TestSwitchTime : nProtocolV05SwitchTime));
102
+ }
103
+
104
+ // Whether a given block is subject to new v0.6 protocol
105
+ // Test against previous block index! (always available)
106
+ bool IsProtocolV06(const CBlockIndex* pindexPrev)
107
+ {
108
+ if (pindexPrev->nTime < (Params().NetworkIDString() != CBaseChainParams::MAIN ? nProtocolV06TestSwitchTime : nProtocolV06SwitchTime))
109
+ return false;
110
+
111
+ // if 900 of the last 1,000 blocks are version 2 or greater (90/100 if testnet):
112
+ // Soft-forking PoS can be dangerous if the super majority is too low
113
+ // The stake majority will decrease after the fork
114
+ // since only coindays of updated nodes will get destroyed.
115
+ if ((Params().NetworkIDString() == CBaseChainParams::MAIN && IsSuperMajority(2, pindexPrev, 900, 1000)) ||
116
+ (Params().NetworkIDString() != CBaseChainParams::MAIN && IsSuperMajority(2, pindexPrev, 90, 100)))
117
+ return true;
118
+
119
+ return false;
120
+ }
121
+
122
+ // Whether a given transaction is subject to new v0.7 protocol
123
+ bool IsProtocolV07(unsigned int nTimeTx)
124
+ {
125
+ bool fTestNet = Params().NetworkIDString() != CBaseChainParams::MAIN;
126
+ return (nTimeTx >= (fTestNet? nProtocolV07TestSwitchTime : nProtocolV07SwitchTime));
127
+ }
128
+
129
+ bool IsBTC16BIPsEnabled(uint32_t nTimeTx)
130
+ {
131
+ bool fTestNet = Params().NetworkIDString() != CBaseChainParams::MAIN;
132
+ return (nTimeTx >= (fTestNet? nBTC16BIPsTestSwitchTime : nBTC16BIPsSwitchTime));
133
+ }
134
+
135
+ // Whether a given timestamp is subject to new v0.9 protocol
136
+ bool IsProtocolV09(unsigned int nTime)
137
+ {
138
+ return (nTime >= (Params().NetworkIDString() != CBaseChainParams::MAIN ? nProtocolV09TestSwitchTime : nProtocolV09SwitchTime));
139
+ }
140
+
141
+ // Whether a given timestamp is subject to new v10 protocol
142
+ bool IsProtocolV10(unsigned int nTime)
143
+ {
144
+ return (nTime >= (Params().NetworkIDString() != CBaseChainParams::MAIN ? nProtocolV10TestSwitchTime : nProtocolV10SwitchTime));
145
+ }
146
+
147
+ // Whether a given timestamp is subject to new v10 protocol
148
+ bool IsProtocolV12(const CBlockIndex* pindexPrev)
149
+ {
150
+ if (pindexPrev->nTime < (Params().NetworkIDString() != CBaseChainParams::MAIN ? nProtocolV12TestSwitchTime : nProtocolV12SwitchTime))
151
+ return false;
152
+
153
+ if ((Params().NetworkIDString() == CBaseChainParams::MAIN && IsSuperMajority(4, pindexPrev, 900, 1000)) ||
154
+ (Params().NetworkIDString() != CBaseChainParams::MAIN && IsSuperMajority(4, pindexPrev, 90, 100)))
155
+ return true;
156
+
157
+ return false;
158
+ }
159
+
160
+ // Get the last stake modifier and its generation time from a given block
161
+ static bool GetLastStakeModifier(const CBlockIndex* pindex, uint64_t& nStakeModifier, int64_t& nModifierTime)
162
+ {
163
+ if (!pindex)
164
+ return error("GetLastStakeModifier: null pindex");
165
+ while (pindex && pindex->pprev && !pindex->GeneratedStakeModifier())
166
+ pindex = pindex->pprev;
167
+ if (!pindex->GeneratedStakeModifier())
168
+ return error("GetLastStakeModifier: no generation at genesis block");
169
+ nStakeModifier = pindex->nStakeModifier;
170
+ nModifierTime = pindex->GetBlockTime();
171
+ return true;
172
+ }
173
+
174
+ // Get selection interval section (in seconds)
175
+ static int64_t GetStakeModifierSelectionIntervalSection(int nSection)
176
+ {
177
+ assert (nSection >= 0 && nSection < 64);
178
+ return (Params().GetConsensus().nModifierInterval * 63 / (63 + ((63 - nSection) * (MODIFIER_INTERVAL_RATIO - 1))));
179
+ }
180
+
181
+ // Get stake modifier selection interval (in seconds)
182
+ static int64_t GetStakeModifierSelectionInterval()
183
+ {
184
+ int64_t nSelectionInterval = 0;
185
+ for (int nSection=0; nSection<64; nSection++)
186
+ nSelectionInterval += GetStakeModifierSelectionIntervalSection(nSection);
187
+ return nSelectionInterval;
188
+ }
189
+
190
+ // select a block from the candidate blocks in vSortedByTimestamp, excluding
191
+ // already selected blocks in vSelectedBlocks, and with timestamp up to
192
+ // nSelectionIntervalStop.
193
+ static bool SelectBlockFromCandidates(
194
+ vector<pair<int64_t, uint256> >& vSortedByTimestamp,
195
+ map<uint256, const CBlockIndex*>& mapSelectedBlocks,
196
+ int64_t nSelectionIntervalStop, uint64_t nStakeModifierPrev,
197
+ const CBlockIndex** pindexSelected,
198
+ CChainState& chainstate)
199
+ {
200
+ bool fSelected = false;
201
+ arith_uint256 hashBest = 0;
202
+ *pindexSelected = (const CBlockIndex*) 0;
203
+ for (const auto& item : vSortedByTimestamp)
204
+ {
205
+ /*
206
+ if (!chainstate.BlockIndex().count(item.second))
207
+ return error("SelectBlockFromCandidates: failed to find block index for candidate block %s", item.second.ToString());
208
+ const CBlockIndex* pindex = pindexSelected.BlockIndex()[item.second];
209
+ */
210
+ const CBlockIndex* pindex = chainstate.m_blockman.LookupBlockIndex(item.second);
211
+ if (!pindex)
212
+ return error("SelectBlockFromCandidates: failed to find block index for candidate block %s", item.second.ToString());
213
+
214
+ if (fSelected && pindex->GetBlockTime() > nSelectionIntervalStop)
215
+ break;
216
+ if (mapSelectedBlocks.count(pindex->GetBlockHash()) > 0)
217
+ continue;
218
+ // compute the selection hash by hashing its proof-hash and the
219
+ // previous proof-of-stake modifier
220
+ uint256 hashProof = pindex->IsProofOfStake()? pindex->hashProofOfStake : pindex->GetBlockHash();
221
+ CDataStream ss(SER_GETHASH, 0);
222
+ ss << hashProof << nStakeModifierPrev;
223
+ arith_uint256 hashSelection = UintToArith256(Hash(ss));
224
+ // the selection hash is divided by 2**32 so that proof-of-stake block
225
+ // is always favored over proof-of-work block. this is to preserve
226
+ // the energy efficiency property
227
+ if (pindex->IsProofOfStake())
228
+ hashSelection >>= 32;
229
+ if (fSelected && hashSelection < hashBest)
230
+ {
231
+ hashBest = hashSelection;
232
+ *pindexSelected = (const CBlockIndex*) pindex;
233
+ }
234
+ else if (!fSelected)
235
+ {
236
+ fSelected = true;
237
+ hashBest = hashSelection;
238
+ *pindexSelected = (const CBlockIndex*) pindex;
239
+ }
240
+ }
241
+ if (gArgs.GetBoolArg("-debug", false) && gArgs.GetBoolArg("-printstakemodifier", false))
242
+ LogPrintf("SelectBlockFromCandidates: selection hash=%s\n", hashBest.ToString());
243
+ return fSelected;
244
+ }
245
+
246
+ // Stake Modifier (hash modifier of proof-of-stake):
247
+ // The purpose of stake modifier is to prevent a txout (coin) owner from
248
+ // computing future proof-of-stake generated by this txout at the time
249
+ // of transaction confirmation. To meet kernel protocol, the txout
250
+ // must hash with a future stake modifier to generate the proof.
251
+ // Stake modifier consists of bits each of which is contributed from a
252
+ // selected block of a given block group in the past.
253
+ // The selection of a block is based on a hash of the block's proof-hash and
254
+ // the previous stake modifier.
255
+ // Stake modifier is recomputed at a fixed time interval instead of every
256
+ // block. This is to make it difficult for an attacker to gain control of
257
+ // additional bits in the stake modifier, even after generating a chain of
258
+ // blocks.
259
+ bool ComputeNextStakeModifier(const CBlockIndex* pindexCurrent, uint64_t &nStakeModifier, bool& fGeneratedStakeModifier, CChainState& chainstate)
260
+ {
261
+ const Consensus::Params& params = Params().GetConsensus();
262
+ const CBlockIndex* pindexPrev = pindexCurrent->pprev;
263
+ nStakeModifier = 0;
264
+ fGeneratedStakeModifier = false;
265
+ if (!pindexPrev)
266
+ {
267
+ fGeneratedStakeModifier = true;
268
+ return true; // genesis block's modifier is 0
269
+ }
270
+ // First find current stake modifier and its generation block time
271
+ // if it's not old enough, return the same stake modifier
272
+ int64_t nModifierTime = 0;
273
+ if (!GetLastStakeModifier(pindexPrev, nStakeModifier, nModifierTime))
274
+ return error("ComputeNextStakeModifier: unable to get last modifier");
275
+ if (gArgs.GetBoolArg("-debug", false))
276
+ LogPrintf("ComputeNextStakeModifier: prev modifier=0x%016x time=%s epoch=%u\n", nStakeModifier, FormatISO8601DateTime(nModifierTime), (unsigned int)nModifierTime);
277
+ if (nModifierTime / params.nModifierInterval >= pindexPrev->GetBlockTime() / params.nModifierInterval)
278
+ {
279
+ if (gArgs.GetBoolArg("-debug", false))
280
+ LogPrintf("ComputeNextStakeModifier: no new interval keep current modifier: pindexPrev nHeight=%d nTime=%u\n", pindexPrev->nHeight, (unsigned int)pindexPrev->GetBlockTime());
281
+ return true;
282
+ }
283
+ if (nModifierTime / params.nModifierInterval >= pindexCurrent->GetBlockTime() / params.nModifierInterval)
284
+ {
285
+ // v0.4+ requires current block timestamp also be in a different modifier interval
286
+ if (IsProtocolV04(pindexCurrent->nTime))
287
+ {
288
+ if (gArgs.GetBoolArg("-debug", false))
289
+ LogPrintf("ComputeNextStakeModifier: (v0.4+) no new interval keep current modifier: pindexCurrent nHeight=%d nTime=%u\n", pindexCurrent->nHeight, (unsigned int)pindexCurrent->GetBlockTime());
290
+ return true;
291
+ }
292
+ else
293
+ {
294
+ if (gArgs.GetBoolArg("-debug", false))
295
+ LogPrintf("ComputeNextStakeModifier: v0.3 modifier at block %s not meeting v0.4+ protocol: pindexCurrent nHeight=%d nTime=%u\n", pindexCurrent->GetBlockHash().ToString(), pindexCurrent->nHeight, (unsigned int)pindexCurrent->GetBlockTime());
296
+ }
297
+ }
298
+
299
+ // Sort candidate blocks by timestamp
300
+ vector<pair<int64_t, uint256> > vSortedByTimestamp;
301
+ vSortedByTimestamp.reserve(64 * params.nModifierInterval / params.nStakeTargetSpacing);
302
+ int64_t nSelectionInterval = GetStakeModifierSelectionInterval();
303
+ int64_t nSelectionIntervalStart = (pindexPrev->GetBlockTime() / params.nModifierInterval) * params.nModifierInterval - nSelectionInterval;
304
+ const CBlockIndex* pindex = pindexPrev;
305
+ while (pindex && pindex->GetBlockTime() >= nSelectionIntervalStart)
306
+ {
307
+ vSortedByTimestamp.push_back(make_pair(pindex->GetBlockTime(), pindex->GetBlockHash()));
308
+ pindex = pindex->pprev;
309
+ }
310
+ int nHeightFirstCandidate = pindex ? (pindex->nHeight + 1) : 0;
311
+
312
+ // Shuffle before sort
313
+ for(int i = vSortedByTimestamp.size() - 1; i > 1; --i)
314
+ std::swap(vSortedByTimestamp[i], vSortedByTimestamp[GetRand(i)]);
315
+
316
+ sort(vSortedByTimestamp.begin(), vSortedByTimestamp.end(), [] (const pair<int64_t, uint256> &a, const pair<int64_t, uint256> &b)
317
+ {
318
+ if (a.first != b.first)
319
+ return a.first < b.first;
320
+ // Timestamp equals - compare block hashes
321
+ const uint32_t *pa = a.second.GetDataPtr();
322
+ const uint32_t *pb = b.second.GetDataPtr();
323
+ int cnt = 256 / 32;
324
+ do {
325
+ --cnt;
326
+ if (pa[cnt] != pb[cnt])
327
+ return pa[cnt] < pb[cnt];
328
+ } while(cnt);
329
+ return false; // Elements are equal
330
+ });
331
+
332
+ // Select 64 blocks from candidate blocks to generate stake modifier
333
+ uint64_t nStakeModifierNew = 0;
334
+ int64_t nSelectionIntervalStop = nSelectionIntervalStart;
335
+ map<uint256, const CBlockIndex*> mapSelectedBlocks;
336
+ for (int nRound=0; nRound<min(64, (int)vSortedByTimestamp.size()); nRound++)
337
+ {
338
+ // add an interval section to the current selection round
339
+ nSelectionIntervalStop += GetStakeModifierSelectionIntervalSection(nRound);
340
+ // select a block from the candidates of current round
341
+ if (!SelectBlockFromCandidates(vSortedByTimestamp, mapSelectedBlocks, nSelectionIntervalStop, nStakeModifier, &pindex, chainstate))
342
+ return error("ComputeNextStakeModifier: unable to select block at round %d", nRound);
343
+ // write the entropy bit of the selected block
344
+ nStakeModifierNew |= (((uint64_t)pindex->GetStakeEntropyBit()) << nRound);
345
+ // add the selected block from candidates to selected list
346
+ mapSelectedBlocks.insert(make_pair(pindex->GetBlockHash(), pindex));
347
+ if (gArgs.GetBoolArg("-debug", false) && gArgs.GetBoolArg("-printstakemodifier", false))
348
+ LogPrintf("ComputeNextStakeModifier: selected round %d stop=%s height=%d bit=%d\n",
349
+ nRound, FormatISO8601DateTime(nSelectionIntervalStop), pindex->nHeight, pindex->GetStakeEntropyBit());
350
+ }
351
+
352
+ // Print selection map for visualization of the selected blocks
353
+ if (gArgs.GetBoolArg("-debug", false) && gArgs.GetBoolArg("-printstakemodifier", false))
354
+ {
355
+ string strSelectionMap = "";
356
+ // '-' indicates proof-of-work blocks not selected
357
+ strSelectionMap.insert(0, pindexPrev->nHeight - nHeightFirstCandidate + 1, '-');
358
+ pindex = pindexPrev;
359
+ while (pindex && pindex->nHeight >= nHeightFirstCandidate)
360
+ {
361
+ // '=' indicates proof-of-stake blocks not selected
362
+ if (pindex->IsProofOfStake())
363
+ strSelectionMap.replace(pindex->nHeight - nHeightFirstCandidate, 1, "=");
364
+ pindex = pindex->pprev;
365
+ }
366
+ for (const auto& item : mapSelectedBlocks)
367
+ {
368
+ // 'S' indicates selected proof-of-stake blocks
369
+ // 'W' indicates selected proof-of-work blocks
370
+ strSelectionMap.replace(item.second->nHeight - nHeightFirstCandidate, 1, item.second->IsProofOfStake()? "S" : "W");
371
+ }
372
+ LogPrintf("ComputeNextStakeModifier: selection height [%d, %d] map %s\n", nHeightFirstCandidate, pindexPrev->nHeight, strSelectionMap);
373
+ }
374
+ if (gArgs.GetBoolArg("-debug", false))
375
+ LogPrintf("ComputeNextStakeModifier: new modifier=0x%016x time=%s\n", nStakeModifierNew, FormatISO8601DateTime(pindexPrev->GetBlockTime()));
376
+
377
+ nStakeModifier = nStakeModifierNew;
378
+ fGeneratedStakeModifier = true;
379
+ return true;
380
+ }
381
+
382
+ // V0.5: Stake modifier used to hash for a stake kernel is chosen as the stake
383
+ // modifier that is (nStakeMinAge minus a selection interval) earlier than the
384
+ // stake, thus at least a selection interval later than the coin generating the
385
+ // kernel, as the generating coin is from at least nStakeMinAge ago.
386
+ static bool GetKernelStakeModifierV05(CBlockIndex* pindexPrev, unsigned int nTimeTx, uint64_t& nStakeModifier, int& nStakeModifierHeight, int64_t& nStakeModifierTime, bool fPrintProofOfStake)
387
+ {
388
+ const Consensus::Params& params = Params().GetConsensus();
389
+ const CBlockIndex* pindex = pindexPrev;
390
+ nStakeModifierHeight = pindex->nHeight;
391
+ nStakeModifierTime = pindex->GetBlockTime();
392
+ int64_t nStakeModifierSelectionInterval = GetStakeModifierSelectionInterval();
393
+
394
+ if (nStakeModifierTime + params.nStakeMinAge - nStakeModifierSelectionInterval <= (int64_t) nTimeTx)
395
+ {
396
+ // Best block is still more than
397
+ // (nStakeMinAge minus a selection interval) older than kernel timestamp
398
+ if (fPrintProofOfStake)
399
+ return error("GetKernelStakeModifier() : best block %s at height %d too old for stake",
400
+ pindex->GetBlockHash().ToString(), pindex->nHeight);
401
+ else
402
+ return false;
403
+ }
404
+ // loop to find the stake modifier earlier by
405
+ // (nStakeMinAge minus a selection interval)
406
+ while (nStakeModifierTime + params.nStakeMinAge - nStakeModifierSelectionInterval >(int64_t) nTimeTx)
407
+ {
408
+ if (!pindex->pprev)
409
+ { // reached genesis block; should not happen
410
+ return error("GetKernelStakeModifier() : reached genesis block");
411
+ }
412
+ pindex = pindex->pprev;
413
+ if (pindex->GeneratedStakeModifier())
414
+ {
415
+ nStakeModifierHeight = pindex->nHeight;
416
+ nStakeModifierTime = pindex->GetBlockTime();
417
+ }
418
+ }
419
+ nStakeModifier = pindex->nStakeModifier;
420
+ return true;
421
+ }
422
+
423
+ // V0.3: Stake modifier used to hash for a stake kernel is chosen as the stake
424
+ // modifier about a selection interval later than the coin generating the kernel
425
+ static bool GetKernelStakeModifierV03(CBlockIndex* pindexPrev, uint256 hashBlockFrom, uint64_t& nStakeModifier, int& nStakeModifierHeight, int64_t& nStakeModifierTime, bool fPrintProofOfStake, CChainState& chainstate)
426
+ {
427
+ const Consensus::Params& params = Params().GetConsensus();
428
+ nStakeModifier = 0;
429
+
430
+ const CBlockIndex* pindexFrom = chainstate.m_blockman.LookupBlockIndex(hashBlockFrom);
431
+ if (!pindexFrom)
432
+ return error("GetKernelStakeModifier() : block not indexed");
433
+
434
+ nStakeModifierHeight = pindexFrom->nHeight;
435
+ nStakeModifierTime = pindexFrom->GetBlockTime();
436
+ int64_t nStakeModifierSelectionInterval = GetStakeModifierSelectionInterval();
437
+
438
+
439
+ // we need to iterate index forward but we cannot depend on chainActive.Next()
440
+ // because there is no guarantee that we are checking blocks in active chain.
441
+ // So, we construct a temporary chain that we will iterate over.
442
+ // pindexFrom - this block contains coins that are used to generate PoS
443
+ // pindexPrev - this is a block that is previous to PoS block that we are checking, you can think of it as tip of our chain
444
+ std::vector<CBlockIndex*> tmpChain;
445
+ int32_t nDepth = pindexPrev->nHeight - (pindexFrom->nHeight-1); // -1 is used to also include pindexFrom
446
+ tmpChain.reserve(nDepth);
447
+ CBlockIndex* it = pindexPrev;
448
+ for (int i=1; i<=nDepth && !chainstate.m_chain.Contains(it); i++) {
449
+ tmpChain.push_back(it);
450
+ it = it->pprev;
451
+ }
452
+ std::reverse(tmpChain.begin(), tmpChain.end());
453
+ size_t n = 0;
454
+
455
+ const CBlockIndex* pindex = pindexFrom;
456
+ // loop to find the stake modifier later by a selection interval
457
+ while (nStakeModifierTime < pindexFrom->GetBlockTime() + nStakeModifierSelectionInterval)
458
+ {
459
+ const CBlockIndex* old_pindex = pindex;
460
+ pindex = (!tmpChain.empty() && pindex->nHeight >= tmpChain[0]->nHeight - 1)? tmpChain[n++] : chainstate.m_chain.Next(pindex);
461
+ if (n > tmpChain.size() || pindex == NULL) // check if tmpChain[n+1] exists
462
+ { // reached best block; may happen if node is behind on block chain
463
+ if (fPrintProofOfStake || (old_pindex->GetBlockTime() + params.nStakeMinAge - nStakeModifierSelectionInterval > GetAdjustedTime()))
464
+ return error("GetKernelStakeModifier() : reached best block %s at height %d from block %s",
465
+ old_pindex->GetBlockHash().ToString(), old_pindex->nHeight, hashBlockFrom.ToString());
466
+ else
467
+ return false;
468
+ }
469
+ if (pindex->GeneratedStakeModifier())
470
+ {
471
+ nStakeModifierHeight = pindex->nHeight;
472
+ nStakeModifierTime = pindex->GetBlockTime();
473
+ }
474
+ }
475
+ nStakeModifier = pindex->nStakeModifier;
476
+ return true;
477
+ }
478
+
479
+ // Get the stake modifier specified by the protocol to hash for a stake kernel
480
+ static bool GetKernelStakeModifier(CBlockIndex* pindexPrev, uint256 hashBlockFrom, unsigned int nTimeTx, uint64_t& nStakeModifier, int& nStakeModifierHeight, int64_t& nStakeModifierTime, bool fPrintProofOfStake, CChainState& chainstate)
481
+ {
482
+ if (IsProtocolV05(nTimeTx))
483
+ return GetKernelStakeModifierV05(pindexPrev, nTimeTx, nStakeModifier, nStakeModifierHeight, nStakeModifierTime, fPrintProofOfStake);
484
+ else
485
+ return GetKernelStakeModifierV03(pindexPrev, hashBlockFrom, nStakeModifier, nStakeModifierHeight, nStakeModifierTime, fPrintProofOfStake, chainstate);
486
+ }
487
+
488
+ // peercoin kernel protocol
489
+ // coinstake must meet hash target according to the protocol:
490
+ // kernel (input 0) must meet the formula
491
+ // hash(nStakeModifier + txPrev.block.nTime + txPrev.offset + txPrev.nTime + txPrev.vout.n + nTime) < bnTarget * nCoinDayWeight
492
+ // this ensures that the chance of getting a coinstake is proportional to the
493
+ // amount of coin age one owns.
494
+ // The reason this hash is chosen is the following:
495
+ // nStakeModifier:
496
+ // (v0.5) uses dynamic stake modifier around 21 days before the kernel,
497
+ // versus static stake modifier about 9 days after the staked
498
+ // coin (txPrev) used in v0.3
499
+ // (v0.3) scrambles computation to make it very difficult to precompute
500
+ // future proof-of-stake at the time of the coin's confirmation
501
+ // (v0.2) nBits (deprecated): encodes all past block timestamps
502
+ // txPrev.block.nTime: prevent nodes from guessing a good timestamp to
503
+ // generate transaction for future advantage
504
+ // txPrev.offset: offset of txPrev inside block, to reduce the chance of
505
+ // nodes generating coinstake at the same time
506
+ // txPrev.nTime: reduce the chance of nodes generating coinstake at the same
507
+ // time
508
+ // txPrev.vout.n: output number of txPrev, to reduce the chance of nodes
509
+ // generating coinstake at the same time
510
+ // block/tx hash should not be used here as they can be generated in vast
511
+ // quantities so as to generate blocks faster, degrading the system back into
512
+ // a proof-of-work situation.
513
+ //
514
+ bool CheckStakeKernelHash(unsigned int nBits, CBlockIndex* pindexPrev, const CBlockHeader& blockFrom, unsigned int nTxPrevOffset, const CTransactionRef& txPrev, const COutPoint& prevout, unsigned int nTimeTx, uint256& hashProofOfStake, bool fPrintProofOfStake, CChainState& chainstate)
515
+ {
516
+ const Consensus::Params& params = Params().GetConsensus();
517
+ unsigned int nTimeBlockFrom = blockFrom.GetBlockTime();
518
+
519
+ if (nTimeTx < (txPrev->nTime? txPrev->nTime : nTimeBlockFrom)) // Transaction timestamp violation
520
+ return error("CheckStakeKernelHash() : nTime violation");
521
+
522
+ if (nTimeBlockFrom + params.nStakeMinAge > nTimeTx) // Min age requirement
523
+ return error("CheckStakeKernelHash() : min age violation");
524
+
525
+ CBigNum bnTargetPerCoinDay;
526
+ bnTargetPerCoinDay.SetCompact(nBits);
527
+ int64_t nValueIn = txPrev->vout[prevout.n].nValue;
528
+ // v0.3 protocol kernel hash weight starts from 0 at the 30-day min age
529
+ // this change increases active coins participating the hash and helps
530
+ // to secure the network when proof-of-stake difficulty is low
531
+ int64_t nTimeWeight = min((int64_t)nTimeTx - (txPrev->nTime? txPrev->nTime : nTimeBlockFrom), params.nStakeMaxAge) - (IsProtocolV03(nTimeTx)? params.nStakeMinAge : 0);
532
+ CBigNum bnCoinDayWeight = CBigNum(nValueIn) * nTimeWeight / COIN / (24 * 60 * 60);
533
+ // Calculate hash
534
+ CDataStream ss(SER_GETHASH, 0);
535
+ uint64_t nStakeModifier = 0;
536
+ int nStakeModifierHeight = 0;
537
+ int64_t nStakeModifierTime = 0;
538
+ if (IsProtocolV03(nTimeTx)) // v0.3 protocol
539
+ {
540
+ if (!GetKernelStakeModifier(pindexPrev, blockFrom.GetHash(), nTimeTx, nStakeModifier, nStakeModifierHeight, nStakeModifierTime, fPrintProofOfStake, chainstate))
541
+ return false;
542
+ ss << nStakeModifier;
543
+ }
544
+ else // v0.2 protocol
545
+ {
546
+ ss << nBits;
547
+ }
548
+
549
+ ss << nTimeBlockFrom << nTxPrevOffset << (txPrev->nTime? txPrev->nTime : nTimeBlockFrom) << prevout.n << nTimeTx;
550
+ hashProofOfStake = Hash(ss);
551
+ if (fPrintProofOfStake)
552
+ {
553
+ if (IsProtocolV03(nTimeTx)) {
554
+ const CBlockIndex* pindexTmp = chainstate.m_blockman.LookupBlockIndex(blockFrom.GetHash());
555
+ LogPrintf("CheckStakeKernelHash() : using modifier 0x%016x at height=%d timestamp=%s for block from height=%d timestamp=%s\n",
556
+ nStakeModifier, nStakeModifierHeight,
557
+ FormatISO8601DateTime(nStakeModifierTime),
558
+ pindexTmp->nHeight,
559
+ FormatISO8601DateTime(blockFrom.GetBlockTime()));
560
+ }
561
+ LogPrintf("CheckStakeKernelHash() : check protocol=%s modifier=0x%016x nTimeBlockFrom=%u nTxPrevOffset=%u nTimeTxPrev=%u nPrevout=%u nTimeTx=%u hashProof=%s\n",
562
+ IsProtocolV05(nTimeTx)? "0.5" : (IsProtocolV03(nTimeTx)? "0.3" : "0.2"),
563
+ IsProtocolV03(nTimeTx)? nStakeModifier : (uint64_t) nBits,
564
+ nTimeBlockFrom, nTxPrevOffset, (txPrev->nTime? txPrev->nTime : nTimeBlockFrom), prevout.n, nTimeTx,
565
+ hashProofOfStake.ToString());
566
+ }
567
+
568
+ // Now check if proof-of-stake hash meets target protocol
569
+ if (CBigNum(hashProofOfStake) > bnCoinDayWeight * bnTargetPerCoinDay)
570
+ return false;
571
+ if (gArgs.GetBoolArg("-debug", false) && !fPrintProofOfStake)
572
+ {
573
+ if (IsProtocolV03(nTimeTx)) {
574
+ const CBlockIndex* pindexTmp = chainstate.m_blockman.LookupBlockIndex(blockFrom.GetHash());
575
+ LogPrintf("CheckStakeKernelHash() : using modifier 0x%016x at height=%d timestamp=%s for block from height=%d timestamp=%s\n",
576
+ nStakeModifier, nStakeModifierHeight,
577
+ FormatISO8601DateTime(nStakeModifierTime),
578
+ pindexTmp->nHeight,
579
+ FormatISO8601DateTime(blockFrom.GetBlockTime()));
580
+ }
581
+ LogPrintf("CheckStakeKernelHash() : pass protocol=%s modifier=0x%016x nTimeBlockFrom=%u nTxPrevOffset=%u nTimeTxPrev=%u nPrevout=%u nTimeTx=%u hashProof=%s\n",
582
+ IsProtocolV03(nTimeTx)? "0.3" : "0.2",
583
+ IsProtocolV03(nTimeTx)? nStakeModifier : (uint64_t) nBits,
584
+ nTimeBlockFrom, nTxPrevOffset, (txPrev->nTime? txPrev->nTime : nTimeBlockFrom), prevout.n, nTimeTx,
585
+ hashProofOfStake.ToString());
586
+ }
587
+ return true;
588
+ }
589
+
590
+ // Check kernel hash target and coinstake signature
591
+ bool CheckProofOfStake(BlockValidationState &state, CBlockIndex* pindexPrev, const CTransactionRef& tx, unsigned int nBits, uint256& hashProofOfStake, unsigned int nTimeTx, CChainState& chainstate)
592
+ {
593
+ if (!tx->IsCoinStake())
594
+ return error("CheckProofOfStake() : called on non-coinstake %s", tx->GetHash().ToString());
595
+
596
+ // Kernel (input 0) must match the stake hash target per coin age (nBits)
597
+ const CTxIn& txin = tx->vin[0];
598
+
599
+ // Transaction index is required to get to block header
600
+ if (!g_txindex)
601
+ return error("CheckProofOfStake() : transaction index not available");
602
+
603
+ // Get transaction index for the previous transaction
604
+ CDiskTxPos postx;
605
+ if (!g_txindex->FindTxPosition(txin.prevout.hash, postx))
606
+ return error("CheckProofOfStake() : tx index not found"); // tx index not found
607
+
608
+ // Read txPrev and header of its block
609
+ CBlockHeader header;
610
+ CTransactionRef txPrev;
611
+ auto it = g_txindex->cachedTxs.find(txin.prevout.hash);
612
+ if (it != g_txindex->cachedTxs.end()) {
613
+ header = it->second.first;
614
+ txPrev = it->second.second;
615
+ } else {
616
+ CAutoFile file(node::OpenBlockFile(postx, true), SER_DISK, CLIENT_VERSION);
617
+ try {
618
+ file >> header;
619
+ fseek(file.Get(), postx.nTxOffset, SEEK_CUR);
620
+ file >> txPrev;
621
+ } catch (std::exception &e) {
622
+ return error("%s() : deserialize or I/O error in CheckProofOfStake()", __PRETTY_FUNCTION__);
623
+ }
624
+ //g_txindex->cachedTxs[txin.prevout.hash] = std::pair(header,txPrev);
625
+ }
626
+
627
+ if (txPrev->GetHash() != txin.prevout.hash)
628
+ return error("%s() : txid mismatch in CheckProofOfStake()", __PRETTY_FUNCTION__);
629
+
630
+ // Verify signature
631
+ {
632
+ int nIn = 0;
633
+ const CTxOut& prevOut = txPrev->vout[tx->vin[nIn].prevout.n];
634
+ TransactionSignatureChecker checker(&(*tx), nIn, prevOut.nValue, PrecomputedTransactionData(*tx), MissingDataBehavior(1));
635
+
636
+ if (!VerifyScript(tx->vin[nIn].scriptSig, prevOut.scriptPubKey, &(tx->vin[nIn].scriptWitness), SCRIPT_VERIFY_P2SH, checker, nullptr))
637
+ return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "invalid-pos-script", strprintf("%s: VerifyScript failed on coinstake %s", __func__, tx->GetHash().ToString()));
638
+ }
639
+
640
+ if (!CheckStakeKernelHash(nBits, pindexPrev, header, postx.nTxOffset + CBlockHeader::NORMAL_SERIALIZE_SIZE, txPrev, txin.prevout, nTimeTx, hashProofOfStake, gArgs.GetBoolArg("-debug", false), chainstate))
641
+ return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "check-kernel-failed", strprintf("CheckProofOfStake() : INFO: check kernel failed on coinstake %s, hashProof=%s", tx->GetHash().ToString(), hashProofOfStake.ToString())); // may occur during initial download or if behind on block chain sync
642
+
643
+ return true;
644
+ }
645
+
646
+ // Check whether the coinstake timestamp meets protocol
647
+ bool CheckCoinStakeTimestamp(int64_t nTimeBlock, int64_t nTimeTx)
648
+ {
649
+ if (IsProtocolV03(nTimeTx)) // v0.3 protocol
650
+ return (nTimeBlock == nTimeTx);
651
+ else // v0.2 protocol
652
+ return ((nTimeTx <= nTimeBlock) && (nTimeBlock <= nTimeTx + MAX_FUTURE_BLOCK_TIME_PREV9));
653
+ }
654
+
655
+ // Get stake modifier checksum
656
+ unsigned int GetStakeModifierChecksum(const CBlockIndex* pindex)
657
+ {
658
+ assert (pindex->pprev || pindex->GetBlockHash() == Params().GetConsensus().hashGenesisBlock);
659
+ // Hash previous checksum with flags, hashProofOfStake and nStakeModifier
660
+ CDataStream ss(SER_GETHASH, 0);
661
+ if (pindex->pprev)
662
+ ss << pindex->pprev->nStakeModifierChecksum;
663
+ ss << pindex->nFlags << pindex->hashProofOfStake << pindex->nStakeModifier;
664
+ arith_uint256 hashChecksum = UintToArith256(Hash(ss));
665
+ hashChecksum >>= (256 - 32);
666
+ return hashChecksum.GetLow64();
667
+ }
668
+
669
+ // Check stake modifier hard checkpoints
670
+ bool CheckStakeModifierCheckpoints(int nHeight, unsigned int nStakeModifierChecksum)
671
+ {
672
+ bool fTestNet = Params().NetworkIDString() == CBaseChainParams::TESTNET;
673
+ if (fTestNet && mapStakeModifierTestnetCheckpoints.count(nHeight))
674
+ return nStakeModifierChecksum == mapStakeModifierTestnetCheckpoints[nHeight];
675
+
676
+ if (!fTestNet && mapStakeModifierCheckpoints.count(nHeight))
677
+ return nStakeModifierChecksum == mapStakeModifierCheckpoints[nHeight];
678
+
679
+ return true;
680
+ }
681
+
682
+ bool IsSuperMajority(int minVersion, const CBlockIndex* pstart, unsigned int nRequired, unsigned int nToCheck)
683
+ {
684
+ return (HowSuperMajority(minVersion, pstart, nRequired, nToCheck) >= nRequired);
685
+ }
686
+
687
+ unsigned int HowSuperMajority(int minVersion, const CBlockIndex* pstart, unsigned int nRequired, unsigned int nToCheck)
688
+ {
689
+ unsigned int nFound = 0;
690
+ for (unsigned int i = 0; i < nToCheck && nFound < nRequired && pstart != NULL; pstart = pstart->pprev )
691
+ {
692
+ if (!pstart->IsProofOfStake())
693
+ continue;
694
+
695
+ if (pstart->nVersion >= minVersion)
696
+ ++nFound;
697
+
698
+ i++;
699
+ }
700
+ return nFound;
701
+ }
702
+
703
+ // peercoin: entropy bit for stake modifier if chosen by modifier
704
+ unsigned int GetStakeEntropyBit(const CBlock& block)
705
+ {
706
+ unsigned int nEntropyBit = 0;
707
+ if (IsProtocolV04(block.nTime))
708
+ {
709
+ nEntropyBit = UintToArith256(block.GetHash()).GetLow64() & 1llu;// last bit of block hash
710
+ if (gArgs.GetBoolArg("-printstakemodifier", false))
711
+ LogPrintf("GetStakeEntropyBit(v0.4+): nTime=%u hashBlock=%s entropybit=%d\n", block.nTime, block.GetHash().ToString(), nEntropyBit);
712
+ }
713
+ else
714
+ {
715
+ // old protocol for entropy bit pre v0.4
716
+ uint160 hashSig = Hash160(block.vchBlockSig);
717
+ if (gArgs.GetBoolArg("-printstakemodifier", false))
718
+ LogPrintf("GetStakeEntropyBit(v0.3): nTime=%u hashSig=%s", block.nTime, hashSig.ToString());
719
+ nEntropyBit = hashSig.GetDataPtr()[4] >> 31; // take the first bit of the hash
720
+ if (gArgs.GetBoolArg("-printstakemodifier", false))
721
+ LogPrintf(" entropybit=%d\n", nEntropyBit);
722
+ }
723
+ return nEntropyBit;
724
+ }
725
+
src/kernel.h ADDED
@@ -0,0 +1,71 @@
1
+ // Copyright (c) 2012-2023 The Peercoin developers
2
+ // Distributed under the MIT software license, see the accompanying
3
+ // file COPYING or http://www.opensource.org/licenses/mit-license.php.
4
+ #ifndef PEERCOIN_KERNEL_H
5
+ #define PEERCOIN_KERNEL_H
6
+
7
+ #include <primitives/transaction.h> // CTransaction(Ref)
8
+
9
+ class CBlockIndex;
10
+ class BlockValidationState;
11
+ class CBlockHeader;
12
+ class CBlock;
13
+ class CChainState;
14
+
15
+
16
+ // MODIFIER_INTERVAL_RATIO:
17
+ // ratio of group interval length between the last group and the first group
18
+ static const int MODIFIER_INTERVAL_RATIO = 3;
19
+
20
+ // Protocol switch time of v0.3 kernel protocol
21
+ extern unsigned int nProtocolV03SwitchTime;
22
+ extern unsigned int nProtocolV03TestSwitchTime;
23
+
24
+ // Whether a given coinstake is subject to new v0.3 protocol
25
+ bool IsProtocolV03(unsigned int nTimeCoinStake);
26
+ // Whether a given block is subject to new v0.4 protocol
27
+ bool IsProtocolV04(unsigned int nTimeBlock);
28
+ // Whether a given transaction is subject to new v0.5 protocol
29
+ bool IsProtocolV05(unsigned int nTimeTx);
30
+ // Whether a given block is subject to new v0.6 protocol
31
+ // Test against previous block index! (always available)
32
+ bool IsProtocolV06(const CBlockIndex *pindexPrev);
33
+ // Whether a given transaction is subject to new v0.7 protocol
34
+ bool IsProtocolV07(unsigned int nTimeTx);
35
+ // Whether a given block is subject to new BIPs from bitcoin 0.16.x
36
+ bool IsBTC16BIPsEnabled(uint32_t nTimeTx);
37
+ // Whether a given timestamp is subject to new v0.9 protocol
38
+ bool IsProtocolV09(unsigned int nTimeTx);
39
+ // Whether a given timestamp is subject to new v10 protocol
40
+ bool IsProtocolV10(unsigned int nTimeTx);
41
+ // Whether a given block is subject to new v12 protocol
42
+ bool IsProtocolV12(const CBlockIndex* pindexPrev);
43
+
44
+ // Compute the hash modifier for proof-of-stake
45
+ bool ComputeNextStakeModifier(const CBlockIndex* pindexCurrent, uint64_t& nStakeModifier, bool& fGeneratedStakeModifier, CChainState& chainstate);
46
+
47
+ // Check whether stake kernel meets hash target
48
+ // Sets hashProofOfStake on success return
49
+ bool CheckStakeKernelHash(unsigned int nBits, CBlockIndex* pindexPrev, const CBlockHeader& blockFrom, unsigned int nTxPrevOffset, const CTransactionRef& txPrev, const COutPoint& prevout, unsigned int nTimeTx, uint256& hashProofOfStake, bool fPrintProofOfStake, CChainState& chainstate);
50
+
51
+ // Check kernel hash target and coinstake signature
52
+ // Sets hashProofOfStake on success return
53
+ bool CheckProofOfStake(BlockValidationState &state, CBlockIndex* pindexPrev, const CTransactionRef &tx, unsigned int nBits, uint256& hashProofOfStake, unsigned int nTimeTx, CChainState& chainstate);
54
+
55
+ // Check whether the coinstake timestamp meets protocol
56
+ bool CheckCoinStakeTimestamp(int64_t nTimeBlock, int64_t nTimeTx);
57
+
58
+ // Get stake modifier checksum
59
+ unsigned int GetStakeModifierChecksum(const CBlockIndex* pindex);
60
+
61
+ // Check stake modifier hard checkpoints
62
+ bool CheckStakeModifierCheckpoints(int nHeight, unsigned int nStakeModifierChecksum);
63
+
64
+ // peercoin: block version supermajority calculation
65
+ bool IsSuperMajority(int minVersion, const CBlockIndex* pstart, unsigned int nRequired, unsigned int nToCheck);
66
+ unsigned int HowSuperMajority(int minVersion, const CBlockIndex* pstart, unsigned int nRequired, unsigned int nToCheck);
67
+
68
+ // peercoin: entropy bit for stake modifier if chosen by modifier
69
+ unsigned int GetStakeEntropyBit(const CBlock& block);
70
+
71
+ #endif // PEERCOIN_KERNEL_H
src/kernelrecord.cpp ADDED
@@ -0,0 +1,120 @@
1
+ #include <kernelrecord.h>
2
+ #include <key_io.h>
3
+ #include <wallet/wallet.h>
4
+ #include <base58.h>
5
+ #include <chainparams.h>
6
+ #include <timedata.h>
7
+ #include <interfaces/wallet.h>
8
+ #include <math.h>
9
+ using namespace std;
10
+
11
+ bool KernelRecord::showTransaction(bool isCoinbase, int depth)
12
+ {
13
+ if (isCoinbase) {
14
+ if (depth < 2)
15
+ return false;
16
+ } else {
17
+ if (depth == 0)
18
+ return false;
19
+ }
20
+
21
+ return true;
22
+ }
23
+
24
+ /*
25
+ * Decompose CWallet transaction to model kernel records.
26
+ */
27
+ vector<KernelRecord> KernelRecord::decomposeOutput(interfaces::Wallet& wallet, const interfaces::WalletTx &wtx)
28
+ {
29
+ vector<KernelRecord> parts;
30
+ int64_t nTime = (wtx.tx->nTime ? wtx.tx->nTime : wtx.time);
31
+ uint256 hash = wtx.tx->GetHash();
32
+ std::map<std::string, std::string> mapValue = wtx.value_map;
33
+
34
+ int numBlocks;
35
+ interfaces::WalletTxStatus status;
36
+ interfaces::WalletOrderForm orderForm;
37
+ bool inMempool;
38
+ wallet.getWalletTxDetails(hash, status, orderForm, inMempool, numBlocks);
39
+
40
+ if (showTransaction(wtx.is_coinbase, status.depth_in_main_chain)) {
41
+ for (size_t nOut = 0; nOut < wtx.tx->vout.size(); nOut++) {
42
+ CTxOut txOut = wtx.tx->vout[nOut];
43
+ if (wallet.txoutIsMine(txOut)) {
44
+ CTxDestination address;
45
+ std::string addrStr;
46
+
47
+ if (ExtractDestination(txOut.scriptPubKey, address)) {
48
+ // Sent to Bitcoin Address
49
+ addrStr = EncodeDestination(address);
50
+ } else {
51
+ // Sent to IP, or other non-address transaction like OP_EVAL
52
+ addrStr = mapValue["to"];
53
+ }
54
+ std::vector<interfaces::WalletTxOut> coins = wallet.getCoins({COutPoint(hash, nOut)});
55
+ bool isSpent = coins.size() >= 1 ? coins[0].is_spent : true;
56
+ parts.push_back(KernelRecord(hash, nTime, addrStr, txOut.nValue, nOut, isSpent));
57
+ }
58
+ }
59
+ }
60
+
61
+ return parts;
62
+ }
63
+
64
+ std::string KernelRecord::getTxID()
65
+ {
66
+ return hash.ToString() + strprintf("-%03d", idx);
67
+ }
68
+
69
+ int64_t KernelRecord::getAge() const
70
+ {
71
+ return (GetAdjustedTime() - nTime) / 86400;
72
+ }
73
+
74
+ int64_t KernelRecord::getCoinAge() const
75
+ {
76
+ const Consensus::Params& params = Params().GetConsensus();
77
+ int nDayWeight = (min((GetAdjustedTime() - nTime), params.nStakeMaxAge) - params.nStakeMinAge) / 86400;
78
+ return max(nValue * nDayWeight / COIN, (int64_t) 0);
79
+ }
80
+
81
+ double KernelRecord::getProbToMintStake(double difficulty, int timeOffset) const
82
+ {
83
+ const Consensus::Params& params = Params().GetConsensus();
84
+ double maxTarget = pow(static_cast<double>(2), 224);
85
+ double target = maxTarget / difficulty;
86
+ int dayWeight = (min((GetAdjustedTime() - nTime) + timeOffset, params.nStakeMaxAge) - params.nStakeMinAge) / 86400;
87
+ uint64_t coinAge = max(nValue * dayWeight / COIN, (int64_t)0);
88
+ return target * coinAge / pow(static_cast<double>(2), 256);
89
+ }
90
+
91
+ double KernelRecord::getProbToMintWithinNMinutes(double difficulty, int minutes)
92
+ {
93
+ if(difficulty != prevDifficulty || minutes != prevMinutes)
94
+ {
95
+ double prob = 1;
96
+ double p;
97
+ int d = minutes / (60 * 24); // Number of full days
98
+ int m = minutes % (60 * 24); // Number of minutes in the last day
99
+ int i, timeOffset;
100
+
101
+ // Probabilities for the first d days
102
+ for(i = 0; i < d; i++)
103
+ {
104
+ timeOffset = i * 86400;
105
+ p = pow(1 - getProbToMintStake(difficulty, timeOffset), 86400);
106
+ prob *= p;
107
+ }
108
+
109
+ // Probability for the m minutes of the last day
110
+ timeOffset = d * 86400;
111
+ p = pow(1 - getProbToMintStake(difficulty, timeOffset), 60 * m);
112
+ prob *= p;
113
+
114
+ prob = 1 - prob;
115
+ prevProbability = prob;
116
+ prevDifficulty = difficulty;
117
+ prevMinutes = minutes;
118
+ }
119
+ return prevProbability;
120
+ }
src/kernelrecord.h ADDED
@@ -0,0 +1,60 @@
1
+ // Copyright (c) 2012-2023 The Peercoin developers
2
+ // Distributed under the MIT software license, see the accompanying
3
+ // file COPYING or http://www.opensource.org/licenses/mit-license.php.
4
+ #ifndef PEERCOIN_KERNELRECORD_H
5
+ #define PEERCOIN_KERNELRECORD_H
6
+
7
+ #include <uint256.h>
8
+ #include <interfaces/wallet.h>
9
+
10
+ namespace wallet {
11
+ class CWallet;
12
+ } // namespace wallet
13
+ //class CWallet;
14
+ using wallet::CWallet;
15
+ class CWalletTx;
16
+
17
+ class KernelRecord
18
+ {
19
+ public:
20
+ KernelRecord():
21
+ hash(), nTime(0), address(""), nValue(0), idx(0), spent(false), prevMinutes(0), prevDifficulty(0), prevProbability(0)
22
+ {
23
+ }
24
+
25
+ KernelRecord(uint256 hash, int64_t nTime):
26
+ hash(hash), nTime(nTime), address(""), nValue(0), idx(0), spent(false), prevMinutes(0), prevDifficulty(0), prevProbability(0)
27
+ {
28
+ }
29
+
30
+ KernelRecord(uint256 hash, int64_t nTime,
31
+ const std::string &address,
32
+ int64_t nValue, int idx, bool spent):
33
+ hash(hash), nTime(nTime), address(address), nValue(nValue),
34
+ idx(idx), spent(spent), prevMinutes(0), prevDifficulty(0), prevProbability(0)
35
+ {
36
+ }
37
+
38
+ static bool showTransaction(bool isCoinbase, int depth);
39
+ static std::vector<KernelRecord> decomposeOutput(interfaces::Wallet &wallet, const interfaces::WalletTx &wtx);
40
+
41
+
42
+ uint256 hash;
43
+ int64_t nTime;
44
+ std::string address;
45
+ int64_t nValue;
46
+ int idx;
47
+ bool spent;
48
+
49
+ std::string getTxID();
50
+ int64_t getAge() const;
51
+ int64_t getCoinAge() const;
52
+ double getProbToMintStake(double difficulty, int timeOffset = 0) const;
53
+ double getProbToMintWithinNMinutes(double difficulty, int minutes);
54
+ protected:
55
+ int prevMinutes;
56
+ double prevDifficulty;
57
+ double prevProbability;
58
+ };
59
+
60
+ #endif // PEERCOIN_KERNELRECORD_H
src/net.cpp CHANGED
@@ -118,6 +118,10 @@ std::map<CNetAddr, LocalServiceInfo> mapLocalHost GUARDED_BY(g_maplocalhost_mute
118
118
  static bool vfLimited[NET_MAX] GUARDED_BY(g_maplocalhost_mutex) = {};
119
119
  std::string strSubVersion;
120
120
 
121
+ // peercoin: temperature to measure how many PoS headers have been sent by this client
122
+ std::map<CNetAddr, int32_t> mapPoSTemperature;
123
+ std::set<std::pair<COutPoint, unsigned int>> setStakeSeen;
124
+
121
125
  void CConnman::AddAddrFetch(const std::string& strDest)
122
126
  {
123
127
  LOCK(m_addr_fetches_mutex);
@@ -3031,6 +3035,7 @@ CNode::CNode(NodeId idIn, ServiceFlags nLocalServicesIn, std::shared_ptr<Sock> s
3031
3035
  nLocalServices(nLocalServicesIn)
3032
3036
  {
3033
3037
  if (inbound_onion) assert(conn_type_in == ConnectionType::INBOUND);
3038
+ lastAcceptedHeader = uint256();
3034
3039
  if (conn_type_in != ConnectionType::BLOCK_RELAY) {
3035
3040
  m_tx_relay = std::make_unique<TxRelay>();
3036
3041
  }
src/net.h CHANGED
@@ -17,7 +17,6 @@
17
17
  #include <net_permissions.h>
18
18
  #include <netaddress.h>
19
19
  #include <netbase.h>
20
- #include <policy/feerate.h>
21
20
  #include <protocol.h>
22
21
  #include <random.h>
23
22
  #include <span.h>
@@ -88,6 +87,10 @@ static constexpr bool DEFAULT_FIXEDSEEDS{true};
88
87
  static const size_t DEFAULT_MAXRECEIVEBUFFER = 5 * 1000;
89
88
  static const size_t DEFAULT_MAXSENDBUFFER = 1 * 1000;
90
89
 
90
+ /** peercoin: Number of consecutive PoS headers are allowed from a single peer. Used to prevent out of memory attack. */
91
+ static const int32_t MAX_CONSECUTIVE_POS_HEADERS = 1000;
92
+
93
+ // const unsigned int POW_HEADER_COOLING = 70; - defined in protocol.cpp, so that it is visible to other files
91
94
  typedef int64_t NodeId;
92
95
 
93
96
  struct AddedNodeInfo
@@ -243,6 +246,8 @@ struct LocalServiceInfo {
243
246
 
244
247
  extern Mutex g_maplocalhost_mutex;
245
248
  extern std::map<CNetAddr, LocalServiceInfo> mapLocalHost GUARDED_BY(g_maplocalhost_mutex);
249
+ extern std::map<CNetAddr, int32_t> mapPoSTemperature;
250
+ extern std::set<std::pair<COutPoint, unsigned int>> setStakeSeen;
246
251
 
247
252
  extern const std::string NET_MESSAGE_COMMAND_OTHER;
248
253
  typedef std::map<std::string, uint64_t> mapMsgCmdSize; //command, total bytes
@@ -598,6 +603,8 @@ public:
598
603
  /** Lowest measured round-trip time. Used as an inbound peer eviction
599
604
  * criterium in CConnman::AttemptToEvictConnection. */
600
605
  std::atomic<std::chrono::microseconds> m_min_ping_time{std::chrono::microseconds::max()};
606
+ // peercoin: used to detect branch switches
607
+ uint256 lastAcceptedHeader;
601
608
 
602
609
  CNode(NodeId id, ServiceFlags nLocalServicesIn, std::shared_ptr<Sock> sock, const CAddress& addrIn, uint64_t nKeyedNetGroupIn, uint64_t nLocalHostNonceIn, const CAddress& addrBindIn, const std::string& addrNameIn, ConnectionType conn_type_in, bool inbound_onion);
603
610
  CNode(const CNode&) = delete;
@@ -959,6 +966,14 @@ public:
959
966
  /** Return true if we should disconnect the peer for failing an inactivity check. */
960
967
  bool ShouldRunInactivityChecks(const CNode& node, std::chrono::seconds now) const;
961
968
 
969
+ /**
970
+ * This is signaled when network activity should cease.
971
+ * A pointer to it is saved in `m_i2p_sam_session`, so make sure that
972
+ * the lifetime of `interruptNet` is not shorter than
973
+ * the lifetime of `m_i2p_sam_session`.
974
+ */
975
+ CThreadInterrupt interruptNet;
976
+
962
977
  private:
963
978
  struct ListenSocket {
964
979
  public:
@@ -1203,14 +1218,6 @@ private:
1203
1218
  Mutex mutexMsgProc;
1204
1219
  std::atomic<bool> flagInterruptMsgProc{false};
1205
1220
 
1206
- /**
1207
- * This is signaled when network activity should cease.
1208
- * A pointer to it is saved in `m_i2p_sam_session`, so make sure that
1209
- * the lifetime of `interruptNet` is not shorter than
1210
- * the lifetime of `m_i2p_sam_session`.
1211
- */
1212
- CThreadInterrupt interruptNet;
1213
-
1214
1221
  /**
1215
1222
  * I2P SAM session.
1216
1223
  * Used to accept incoming and make outgoing I2P connections.
src/net_processing.cpp CHANGED
@@ -9,17 +9,16 @@
9
9
  #include <banman.h>
10
10
  #include <blockencodings.h>
11
11
  #include <blockfilter.h>
12
+ #include <chain.h>
12
13
  #include <chainparams.h>
13
14
  #include <consensus/amount.h>
14
15
  #include <consensus/validation.h>
15
- #include <deploymentstatus.h>
16
16
  #include <hash.h>
17
17
  #include <index/blockfilterindex.h>
18
18
  #include <merkleblock.h>
19
19
  #include <netbase.h>
20
20
  #include <netmessagemaker.h>
21
21
  #include <node/blockstorage.h>
22
- #include <policy/fees.h>
23
22
  #include <policy/policy.h>
24
23
  #include <primitives/block.h>
25
24
  #include <primitives/transaction.h>
@@ -45,10 +44,11 @@
45
44
  #include <optional>
46
45
  #include <typeinfo>
47
46
 
47
+ #include <kernel.h>
48
+
48
49
  using node::ReadBlockFromDisk;
49
50
  using node::ReadRawBlockFromDisk;
50
51
  using node::fImporting;
51
- using node::fPruneMode;
52
52
  using node::fReindex;
53
53
 
54
54
  /** How long to cache transactions in mapRelay for normal relay */
@@ -415,7 +415,7 @@ private:
415
415
  void RelayAddress(NodeId originator, const CAddress& addr, bool fReachable);
416
416
 
417
417
  /** Send `feefilter` message. */
418
- void MaybeSendFeefilter(CNode& node, std::chrono::microseconds current_time) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
418
+ // void MaybeSendFeefilter(CNode& node, std::chrono::microseconds current_time) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
419
419
 
420
420
  const CChainParams& m_chainparams;
421
421
  CConnman& m_connman;
@@ -594,6 +594,13 @@ private:
594
594
  TxOrphanage m_orphanage;
595
595
 
596
596
  void AddToCompactExtraTransactions(const CTransactionRef& tx) EXCLUSIVE_LOCKS_REQUIRED(g_cs_orphans);
597
+ /** peercoin: blocks that are waiting to be processed, the key points to previous CBlockIndex entry */
598
+ struct WaitElement {
599
+ std::shared_ptr<CBlock> pblock;
600
+ int64_t time;
601
+ };
602
+ std::map<CBlockIndex*, WaitElement> mapBlocksWait;
603
+
597
604
 
598
605
  /** Orphan/conflicted/etc transactions that are kept for compact block reconstruction.
599
606
  * The last -blockreconstructionextratxn/DEFAULT_BLOCK_RECONSTRUCTION_EXTRA_TXN of
@@ -1004,8 +1011,8 @@ void PeerManagerImpl::ProcessBlockAvailability(NodeId nodeid) {
1004
1011
 
1005
1012
  if (!state->hashLastUnknownBlock.IsNull()) {
1006
1013
  const CBlockIndex* pindex = m_chainman.m_blockman.LookupBlockIndex(state->hashLastUnknownBlock);
1007
- if (pindex && pindex->nChainWork > 0) {
1008
- if (state->pindexBestKnownBlock == nullptr || pindex->nChainWork >= state->pindexBestKnownBlock->nChainWork) {
1014
+ if (pindex && pindex->nChainTrust > 0) {
1015
+ if (state->pindexBestKnownBlock == nullptr || pindex->nChainTrust >= state->pindexBestKnownBlock->nChainTrust) {
1009
1016
  state->pindexBestKnownBlock = pindex;
1010
1017
  }
1011
1018
  state->hashLastUnknownBlock.SetNull();
@@ -1020,9 +1027,9 @@ void PeerManagerImpl::UpdateBlockAvailability(NodeId nodeid, const uint256 &hash
1020
1027
  ProcessBlockAvailability(nodeid);
1021
1028
 
1022
1029
  const CBlockIndex* pindex = m_chainman.m_blockman.LookupBlockIndex(hash);
1023
- if (pindex && pindex->nChainWork > 0) {
1030
+ if (pindex && pindex->nChainTrust > 0) {
1024
1031
  // An actually better block was announced.
1025
- if (state->pindexBestKnownBlock == nullptr || pindex->nChainWork >= state->pindexBestKnownBlock->nChainWork) {
1032
+ if (state->pindexBestKnownBlock == nullptr || pindex->nChainTrust >= state->pindexBestKnownBlock->nChainTrust) {
1026
1033
  state->pindexBestKnownBlock = pindex;
1027
1034
  }
1028
1035
  } else {
@@ -1043,7 +1050,7 @@ void PeerManagerImpl::FindNextBlocksToDownload(NodeId nodeid, unsigned int count
1043
1050
  // Make sure pindexBestKnownBlock is up to date, we'll need it.
1044
1051
  ProcessBlockAvailability(nodeid);
1045
1052
 
1046
- if (state->pindexBestKnownBlock == nullptr || state->pindexBestKnownBlock->nChainWork < m_chainman.ActiveChain().Tip()->nChainWork || state->pindexBestKnownBlock->nChainWork < nMinimumChainWork) {
1053
+ if (state->pindexBestKnownBlock == nullptr || state->pindexBestKnownBlock->nChainTrust < m_chainman.ActiveChain().Tip()->nChainTrust || state->pindexBestKnownBlock->nChainTrust < nMinimumChainWork) {
1047
1054
  // This peer has nothing interesting.
1048
1055
  return;
1049
1056
  }
@@ -1060,7 +1067,6 @@ void PeerManagerImpl::FindNextBlocksToDownload(NodeId nodeid, unsigned int count
1060
1067
  if (state->pindexLastCommonBlock == state->pindexBestKnownBlock)
1061
1068
  return;
1062
1069
 
1063
- const Consensus::Params& consensusParams = m_chainparams.GetConsensus();
1064
1070
  std::vector<const CBlockIndex*> vToFetch;
1065
1071
  const CBlockIndex *pindexWalk = state->pindexLastCommonBlock;
1066
1072
  // Never fetch further than the best block we know the peer has, or more than BLOCK_DOWNLOAD_WINDOW + 1 beyond the last
@@ -1084,13 +1090,13 @@ void PeerManagerImpl::FindNextBlocksToDownload(NodeId nodeid, unsigned int count
1084
1090
  // Iterate over those blocks in vToFetch (in forward direction), adding the ones that
1085
1091
  // are not yet downloaded and not in flight to vBlocks. In the meantime, update
1086
1092
  // pindexLastCommonBlock as long as all ancestors are already downloaded, or if it's
1087
- // already part of our chain (and therefore don't need it even if pruned).
1093
+ // already part of our chain.
1088
1094
  for (const CBlockIndex* pindex : vToFetch) {
1089
1095
  if (!pindex->IsValid(BLOCK_VALID_TREE)) {
1090
1096
  // We consider the chain that this peer is on invalid.
1091
1097
  return;
1092
1098
  }
1093
- if (!State(nodeid)->fHaveWitness && DeploymentActiveAt(*pindex, consensusParams, Consensus::DEPLOYMENT_SEGWIT)) {
1099
+ if (!State(nodeid)->fHaveWitness && IsBTC16BIPsEnabled(pindex->nTime)) {
1094
1100
  // We wouldn't download this block or its descendants from this peer.
1095
1101
  return;
1096
1102
  }
@@ -1594,7 +1600,7 @@ void PeerManagerImpl::NewPoWValidBlock(const CBlockIndex *pindex, const std::sha
1594
1600
  return;
1595
1601
  nHighestFastAnnounce = pindex->nHeight;
1596
1602
 
1597
- bool fWitnessEnabled = DeploymentActiveAt(*pindex, m_chainparams.GetConsensus(), Consensus::DEPLOYMENT_SEGWIT);
1603
+ bool fWitnessEnabled = IsBTC16BIPsEnabled(pindex->nTime);
1598
1604
  uint256 hashBlock(pblock->GetHash());
1599
1605
 
1600
1606
  {
@@ -1870,15 +1876,14 @@ void PeerManagerImpl::ProcessGetBlockData(CNode& pfrom, Peer& peer, const CInv&
1870
1876
  pfrom.fDisconnect = true;
1871
1877
  return;
1872
1878
  }
1873
- // Pruned nodes may have deleted the block, so check whether
1874
- // it's available before trying to send.
1879
+ // Check whether the block is available before trying to send.
1875
1880
  if (!(pindex->nStatus & BLOCK_HAVE_DATA)) {
1876
1881
  return;
1877
1882
  }
1878
1883
  std::shared_ptr<const CBlock> pblock;
1879
1884
  if (a_recent_block && a_recent_block->GetHash() == pindex->GetBlockHash()) {
1880
1885
  pblock = a_recent_block;
1881
- } else if (inv.IsMsgWitnessBlk()) {
1886
+ } /* else if (inv.IsMsgWitnessBlk()) {
1882
1887
  // Fast-path: in this case it is possible to serve the block directly from disk,
1883
1888
  // as the network format matches the format on disk
1884
1889
  std::vector<uint8_t> block_data;
@@ -1887,7 +1892,7 @@ void PeerManagerImpl::ProcessGetBlockData(CNode& pfrom, Peer& peer, const CInv&
1887
1892
  }
1888
1893
  m_connman.PushMessage(&pfrom, msgMaker.Make(NetMsgType::BLOCK, Span{block_data}));
1889
1894
  // Don't set pblock as we've sent the block
1890
- } else {
1895
+ } */ else {
1891
1896
  // Send block from disk
1892
1897
  std::shared_ptr<CBlock> pblockRead = std::make_shared<CBlock>();
1893
1898
  if (!ReadBlockFromDisk(*pblockRead, pindex, m_chainparams.GetConsensus())) {
@@ -1951,8 +1956,11 @@ void PeerManagerImpl::ProcessGetBlockData(CNode& pfrom, Peer& peer, const CInv&
1951
1956
  // Send immediately. This must send even if redundant,
1952
1957
  // and we want it right after the last block so they don't
1953
1958
  // wait for other stuff first.
1959
+ // peercoin: send latest proof-of-work block to allow the
1960
+ // download node to accept as orphan (proof-of-stake
1961
+ // block might be rejected by stake connection check)
1954
1962
  std::vector<CInv> vInv;
1955
- vInv.push_back(CInv(MSG_BLOCK, m_chainman.ActiveChain().Tip()->GetBlockHash()));
1963
+ vInv.push_back(CInv(MSG_BLOCK, GetLastBlockIndex(m_chainman.ActiveChain().Tip(), false)->GetBlockHash()));
1956
1964
  m_connman.PushMessage(&pfrom, msgMaker.Make(NetMsgType::INV, vInv));
1957
1965
  peer.m_continuation_block.SetNull();
1958
1966
  }
@@ -2164,13 +2172,15 @@ void PeerManagerImpl::ProcessHeadersMessage(CNode& pfrom, const Peer& peer,
2164
2172
  }
2165
2173
  }
2166
2174
 
2175
+ int32_t& nPoSTemperature = mapPoSTemperature[pfrom.addr];
2167
2176
  BlockValidationState state;
2168
- if (!m_chainman.ProcessNewBlockHeaders(headers, state, m_chainparams, &pindexLast)) {
2177
+ if (!m_chainman.ProcessNewBlockHeaders(nPoSTemperature, pfrom.lastAcceptedHeader, headers, state, m_chainparams, &pindexLast)) {
2169
2178
  if (state.IsInvalid()) {
2170
2179
  MaybePunishNodeForBlock(pfrom.GetId(), state, via_compact_block, "invalid header received");
2171
2180
  return;
2172
2181
  }
2173
2182
  }
2183
+ pfrom.lastAcceptedHeader = headers.back().GetHash();
2174
2184
 
2175
2185
  {
2176
2186
  LOCK(cs_main);
@@ -2187,7 +2197,7 @@ void PeerManagerImpl::ProcessHeadersMessage(CNode& pfrom, const Peer& peer,
2187
2197
  // because it is set in UpdateBlockAvailability. Some nullptr checks
2188
2198
  // are still present, however, as belt-and-suspenders.
2189
2199
 
2190
- if (received_new_header && pindexLast->nChainWork > m_chainman.ActiveChain().Tip()->nChainWork) {
2200
+ if (received_new_header && pindexLast->nChainTrust > m_chainman.ActiveChain().Tip()->nChainTrust) {
2191
2201
  nodestate->m_last_block_announcement = GetTime();
2192
2202
  }
2193
2203
 
@@ -2202,14 +2212,14 @@ void PeerManagerImpl::ProcessHeadersMessage(CNode& pfrom, const Peer& peer,
2202
2212
 
2203
2213
  // If this set of headers is valid and ends in a block with at least as
2204
2214
  // much work as our tip, download as much as possible.
2205
- if (CanDirectFetch() && pindexLast->IsValid(BLOCK_VALID_TREE) && m_chainman.ActiveChain().Tip()->nChainWork <= pindexLast->nChainWork) {
2215
+ if (CanDirectFetch() && pindexLast->IsValid(BLOCK_VALID_TREE) && m_chainman.ActiveChain().Tip()->nChainTrust <= pindexLast->nChainTrust) {
2206
2216
  std::vector<const CBlockIndex*> vToFetch;
2207
2217
  const CBlockIndex *pindexWalk = pindexLast;
2208
2218
  // Calculate all the blocks we'd need to switch to pindexLast, up to a limit.
2209
2219
  while (pindexWalk && !m_chainman.ActiveChain().Contains(pindexWalk) && vToFetch.size() <= MAX_BLOCKS_IN_TRANSIT_PER_PEER) {
2210
2220
  if (!(pindexWalk->nStatus & BLOCK_HAVE_DATA) &&
2211
2221
  !IsBlockRequested(pindexWalk->GetBlockHash()) &&
2212
- (!DeploymentActiveAt(*pindexWalk, m_chainparams.GetConsensus(), Consensus::DEPLOYMENT_SEGWIT) || State(pfrom.GetId())->fHaveWitness)) {
2222
+ (!IsBTC16BIPsEnabled(pindexWalk->nTime) || State(pfrom.GetId())->fHaveWitness)) {
2213
2223
  // We don't have this block, and it's not yet in flight.
2214
2224
  vToFetch.push_back(pindexWalk);
2215
2225
  }
@@ -2259,7 +2269,7 @@ void PeerManagerImpl::ProcessHeadersMessage(CNode& pfrom, const Peer& peer,
2259
2269
  if (m_chainman.ActiveChainstate().IsInitialBlockDownload() && nCount != MAX_HEADERS_RESULTS) {
2260
2270
  // When nCount < MAX_HEADERS_RESULTS, we know we have no more
2261
2271
  // headers to fetch from this peer.
2262
- if (nodestate->pindexBestKnownBlock && nodestate->pindexBestKnownBlock->nChainWork < nMinimumChainWork) {
2272
+ if (nodestate->pindexBestKnownBlock && nodestate->pindexBestKnownBlock->nChainTrust < nMinimumChainWork) {
2263
2273
  // This peer has too little work on their headers chain to help
2264
2274
  // us sync -- disconnect if it is an outbound disconnection
2265
2275
  // candidate.
@@ -2281,7 +2291,7 @@ void PeerManagerImpl::ProcessHeadersMessage(CNode& pfrom, const Peer& peer,
2281
2291
  // thus always subject to eviction under the bad/lagging chain logic.
2282
2292
  // See ChainSyncTimeoutState.
2283
2293
  if (!pfrom.fDisconnect && pfrom.IsFullOutboundConn() && nodestate->pindexBestKnownBlock != nullptr) {
2284
- if (m_outbound_peers_with_protect_from_disconnect < MAX_OUTBOUND_PEERS_TO_PROTECT_FROM_DISCONNECT && nodestate->pindexBestKnownBlock->nChainWork >= m_chainman.ActiveChain().Tip()->nChainWork && !nodestate->m_chain_sync.m_protect) {
2294
+ if (m_outbound_peers_with_protect_from_disconnect < MAX_OUTBOUND_PEERS_TO_PROTECT_FROM_DISCONNECT && nodestate->pindexBestKnownBlock->nChainTrust >= m_chainman.ActiveChain().Tip()->nChainTrust && !nodestate->m_chain_sync.m_protect) {
2285
2295
  LogPrint(BCLog::NET, "Protecting outbound peer=%d from eviction\n", pfrom.GetId());
2286
2296
  nodestate->m_chain_sync.m_protect = true;
2287
2297
  ++m_outbound_peers_with_protect_from_disconnect;
@@ -2560,9 +2570,17 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
2560
2570
  PeerRef peer = GetPeerRef(pfrom.GetId());
2561
2571
  if (peer == nullptr) return;
2562
2572
 
2573
+ // set deserialization mode to read PoS flag in headers
2574
+ vRecv.SetType(vRecv.GetType() | SER_POSMARKER);
2575
+
2563
2576
  if (msg_type == NetMsgType::VERSION) {
2564
- if (pfrom.nVersion != 0) {
2565
- LogPrint(BCLog::NET, "redundant version message from peer=%d\n", pfrom.GetId());
2577
+ auto it = mapPoSTemperature.find(pfrom.addr);
2578
+ if (it == mapPoSTemperature.end())
2579
+ mapPoSTemperature[pfrom.addr] = MAX_CONSECUTIVE_POS_HEADERS/4;
2580
+ // Each connection can only send one version message
2581
+ if (pfrom.nVersion != 0)
2582
+ {
2583
+ Misbehaving(pfrom.GetId(), 1, "redundant version message");
2566
2584
  return;
2567
2585
  }
2568
2586
 
@@ -3016,13 +3034,11 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
3016
3034
  for (CInv& inv : vInv) {
3017
3035
  if (interruptMsgProc) return;
3018
3036
 
3019
- // Ignore INVs that don't match wtxidrelay setting.
3020
- // Note that orphan parent fetching always uses MSG_TX GETDATAs regardless of the wtxidrelay setting.
3021
- // This is fine as no INV messages are involved in that process.
3037
+ // ignore INVs that don't match wtxidrelay setting
3022
3038
  if (State(pfrom.GetId())->m_wtxid_relay) {
3023
- if (inv.IsMsgTx()) continue;
3039
+ if (inv.type == MSG_TX) continue;
3024
3040
  } else {
3025
- if (inv.IsMsgWtx()) continue;
3041
+ if (inv.type == MSG_WTX) continue;
3026
3042
  }
3027
3043
 
3028
3044
  if (inv.IsMsgBlk()) {
@@ -3134,14 +3150,10 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
3134
3150
  if (pindex->GetBlockHash() == hashStop)
3135
3151
  {
3136
3152
  LogPrint(BCLog::NET, " getblocks stopping at %d %s\n", pindex->nHeight, pindex->GetBlockHash().ToString());
3137
- break;
3138
- }
3139
- // If pruning, don't inv blocks unless we have on disk and are likely to still have
3140
- // for some reasonable time window (1 hour) that block relay might require.
3141
- const int nPrunedBlocksLikelyToHave = MIN_BLOCKS_TO_KEEP - 3600 / m_chainparams.GetConsensus().nPowTargetSpacing;
3142
- if (fPruneMode && (!(pindex->nStatus & BLOCK_HAVE_DATA) || pindex->nHeight <= m_chainman.ActiveChain().Tip()->nHeight - nPrunedBlocksLikelyToHave))
3143
- {
3144
- LogPrint(BCLog::NET, " getblocks stopping, pruned or too old block at %d %s\n", pindex->nHeight, pindex->GetBlockHash().ToString());
3153
+ // peercoin: tell downloading node about the latest block if it's
3154
+ // without risk being rejected due to stake connection check
3155
+ if (hashStop != m_chainman.ActiveChain().Tip()->GetBlockHash() && pindex->GetBlockTime() + Params().GetConsensus().nStakeMinAge > m_chainman.ActiveChain().Tip()->GetBlockTime())
3156
+ WITH_LOCK(peer->m_block_inv_mutex, peer->m_blocks_for_inv_relay.push_back(pindex->GetBlockHash()));
3145
3157
  break;
3146
3158
  }
3147
3159
  WITH_LOCK(peer->m_block_inv_mutex, peer->m_blocks_for_inv_relay.push_back(pindex->GetBlockHash()));
@@ -3517,15 +3529,24 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
3517
3529
  }
3518
3530
  }
3519
3531
 
3532
+ int32_t& nPoSTemperature = mapPoSTemperature[pfrom.addr];
3520
3533
  const CBlockIndex *pindex = nullptr;
3521
3534
  BlockValidationState state;
3522
- if (!m_chainman.ProcessNewBlockHeaders({cmpctblock.header}, state, m_chainparams, &pindex)) {
3535
+ if (!m_chainman.ProcessNewBlockHeaders(nPoSTemperature, m_chainman.ActiveChain().Tip()->GetBlockHash(), {cmpctblock.header}, state, m_chainparams, &pindex)) {
3523
3536
  if (state.IsInvalid()) {
3524
3537
  MaybePunishNodeForBlock(pfrom.GetId(), state, /*via_compact_block*/ true, "invalid header via cmpctblock");
3525
3538
  return;
3526
3539
  }
3527
3540
  }
3528
3541
 
3542
+ if (nPoSTemperature >= MAX_CONSECUTIVE_POS_HEADERS) {
3543
+ nPoSTemperature = (MAX_CONSECUTIVE_POS_HEADERS*3)/4;
3544
+ if (Params().NetworkIDString() != "test") {
3545
+ Misbehaving(pfrom.GetId(), 100, "too many consecutive pos headers");
3546
+ return;
3547
+ }
3548
+ }
3549
+
3529
3550
  // When we succeed in decoding a block's txids from a cmpctblock
3530
3551
  // message we typically jump to the BLOCKTXN handling code, with a
3531
3552
  // dummy (empty) BLOCKTXN message, to re-use the logic there in
@@ -3552,7 +3573,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
3552
3573
 
3553
3574
  // If this was a new header with more work than our tip, update the
3554
3575
  // peer's last block announcement time
3555
- if (received_new_header && pindex->nChainWork > m_chainman.ActiveChain().Tip()->nChainWork) {
3576
+ if (received_new_header && pindex->nChainTrust > m_chainman.ActiveChain().Tip()->nChainTrust) {
3556
3577
  nodestate->m_last_block_announcement = GetTime();
3557
3578
  }
3558
3579
 
@@ -3562,8 +3583,8 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
3562
3583
  if (pindex->nStatus & BLOCK_HAVE_DATA) // Nothing to do here
3563
3584
  return;
3564
3585
 
3565
- if (pindex->nChainWork <= m_chainman.ActiveChain().Tip()->nChainWork || // We know something better
3566
- pindex->nTx != 0) { // We had this block at some point, but pruned it
3586
+ if (pindex->nChainTrust <= m_chainman.ActiveChain().Tip()->nChainTrust || // We know something better
3587
+ pindex->nTx != 0) { // We had this block at some point
3567
3588
  if (fAlreadyInFlight) {
3568
3589
  // We requested this block for some reason, but our mempool will probably be useless
3569
3590
  // so we just grab the block via normal getdata
@@ -3579,7 +3600,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
3579
3600
  return;
3580
3601
  }
3581
3602
 
3582
- if (DeploymentActiveAt(*pindex, m_chainparams.GetConsensus(), Consensus::DEPLOYMENT_SEGWIT) && !nodestate->fSupportsDesiredCmpctVersion) {
3603
+ if (IsBTC16BIPsEnabled(pindex->nTime) && !nodestate->fSupportsDesiredCmpctVersion) {
3583
3604
  // Don't bother trying to process compact blocks from v1 peers
3584
3605
  // after segwit activates.
3585
3606
  return;
@@ -3797,9 +3818,32 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
3797
3818
  return;
3798
3819
  }
3799
3820
  headers.resize(nCount);
3800
- for (unsigned int n = 0; n < nCount; n++) {
3801
- vRecv >> headers[n];
3802
- ReadCompactSize(vRecv); // ignore tx count; assume it is 0.
3821
+ {
3822
+ LOCK(cs_main);
3823
+ int32_t& nPoSTemperature = mapPoSTemperature[pfrom.addr];
3824
+ int nTmpPoSTemperature = nPoSTemperature;
3825
+ for (unsigned int n = 0; n < nCount; n++) {
3826
+ vRecv >> headers[n];
3827
+ ReadCompactSize(vRecv); // ignore tx count; assume it is 0.
3828
+ ReadCompactSize(vRecv); // needed for vchBlockSig.
3829
+
3830
+ // peercoin: quick check to see if we should ban peers for PoS spam
3831
+ // note: at this point we don't know if PoW headers are valid - we just assume they are
3832
+ // so we need to update pfrom->nPoSTemperature once we actualy check them
3833
+ bool fPoS = headers[n].nFlags & CBlockIndex::BLOCK_PROOF_OF_STAKE;
3834
+ nTmpPoSTemperature += fPoS ? 1 : -POW_HEADER_COOLING;
3835
+ // peer cannot cool himself by PoW headers from other branches
3836
+ if (n == 0 && !fPoS && headers[n].hashPrevBlock != pfrom.lastAcceptedHeader)
3837
+ nTmpPoSTemperature += POW_HEADER_COOLING;
3838
+ nTmpPoSTemperature = std::max(nTmpPoSTemperature, 0);
3839
+ if (nTmpPoSTemperature >= MAX_CONSECUTIVE_POS_HEADERS) {
3840
+ nPoSTemperature = (MAX_CONSECUTIVE_POS_HEADERS*3)/4;
3841
+ if (Params().NetworkIDString() != "test") {
3842
+ Misbehaving(pfrom.GetId(), 100, "too many consecutive pos headers");
3843
+ return;
3844
+ }
3845
+ }
3846
+ }
3803
3847
  }
3804
3848
 
3805
3849
  return ProcessHeadersMessage(pfrom, *peer, headers, /*via_compact_block=*/false);
@@ -3813,25 +3857,115 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
3813
3857
  return;
3814
3858
  }
3815
3859
 
3816
- std::shared_ptr<CBlock> pblock = std::make_shared<CBlock>();
3817
- vRecv >> *pblock;
3818
3860
 
3819
- LogPrint(BCLog::NET, "received block %s peer=%d\n", pblock->GetHash().ToString(), pfrom.GetId());
3861
+ std::shared_ptr<CBlock> pblock2 = std::make_shared<CBlock>();
3862
+ vRecv >> *pblock2;
3863
+ int64_t nTimeNow = GetTimeSeconds();
3864
+
3865
+ LogPrint(BCLog::NET, "received block %s peer=%d\n", pblock2->GetHash().ToString(), pfrom.GetId());
3820
3866
 
3821
- bool forceProcessing = false;
3822
- const uint256 hash(pblock->GetHash());
3823
3867
  {
3868
+ const uint256 hash2(pblock2->GetHash());
3824
3869
  LOCK(cs_main);
3825
- // Always process the block if we requested it, since we may
3826
- // need it even when it's not a candidate for a new best tip.
3827
- forceProcessing = IsBlockRequested(hash);
3828
- RemoveBlockRequest(hash);
3829
- // mapBlockSource is only used for punishing peers and setting
3830
- // which peers send us compact blocks, so the race between here and
3831
- // cs_main in ProcessNewBlock is fine.
3832
- mapBlockSource.emplace(hash, std::make_pair(pfrom.GetId(), true));
3833
- }
3834
- ProcessBlock(pfrom, pblock, forceProcessing);
3870
+ bool fRequested = mapBlocksInFlight.count(hash2);
3871
+
3872
+ CBlockIndex* headerPrev = m_chainman.m_blockman.LookupBlockIndex(pblock2->hashPrevBlock);
3873
+ if (!headerPrev) {
3874
+ LogPrint(BCLog::NET, "previous header not found");
3875
+ return;
3876
+ }
3877
+
3878
+ if (!fRequested) {
3879
+ int32_t& nPoSTemperature = mapPoSTemperature[pfrom.addr];
3880
+ if (nPoSTemperature >= MAX_CONSECUTIVE_POS_HEADERS) {
3881
+ nPoSTemperature = (MAX_CONSECUTIVE_POS_HEADERS*3)/4;
3882
+ if (Params().NetworkIDString() != "test") {
3883
+ Misbehaving(pfrom.GetId(), 100, "too many consecutive pos headers");
3884
+ return;
3885
+ }
3886
+ }
3887
+
3888
+ if (pblock2->IsProofOfStake() && !m_chainman.ActiveChainstate().IsInitialBlockDownload())
3889
+ nPoSTemperature += 1;
3890
+
3891
+ if (!headerPrev->IsValid(BLOCK_VALID_TRANSACTIONS)) {
3892
+ RemoveBlockRequest(hash2);
3893
+ LogPrint(BCLog::NET, "this block does not connect to any valid known blocks");
3894
+ return;
3895
+ }
3896
+ }
3897
+ // peercoin: store in memory until we can connect it to some chain
3898
+ WaitElement we; we.pblock = pblock2; we.time = nTimeNow;
3899
+ mapBlocksWait[headerPrev] = we;
3900
+ }
3901
+
3902
+ static CBlockIndex* pindexLastAccepted = nullptr;
3903
+ if (pindexLastAccepted == nullptr)
3904
+ pindexLastAccepted = m_chainman.ActiveChain().Tip();
3905
+ bool fContinue = true;
3906
+
3907
+ // peercoin: accept as many blocks as we possibly can from mapBlocksWait
3908
+ while (fContinue) {
3909
+ fContinue = false;
3910
+ bool fSelected = false;
3911
+ bool forceProcessing = false;
3912
+ CBlockIndex* pindexPrev;
3913
+ std::shared_ptr<CBlock> pblock;
3914
+
3915
+ {
3916
+ LOCK(cs_main);
3917
+ // peercoin: try to select next block in a constant time
3918
+ std::map<CBlockIndex*, WaitElement>::iterator it = mapBlocksWait.find(pindexLastAccepted);
3919
+ if (it != mapBlocksWait.end() && pindexLastAccepted != nullptr) {
3920
+ pindexPrev = it->first;
3921
+ pblock = it->second.pblock;
3922
+ mapBlocksWait.erase(pindexPrev);
3923
+ fContinue = true;
3924
+ fSelected = true;
3925
+ } else
3926
+ // otherwise: try to scan for it
3927
+ for (auto& pair : mapBlocksWait) {
3928
+ pindexPrev = pair.first;
3929
+ pblock = pair.second.pblock;
3930
+ const uint256 hash(pblock->GetHash());
3931
+ // remove blocks that were not connected in 60 seconds
3932
+ if (nTimeNow > pair.second.time + 60) {
3933
+ mapBlocksWait.erase(pindexPrev);
3934
+ fContinue = true;
3935
+ RemoveBlockRequest(hash);
3936
+ break;
3937
+ }
3938
+ if (!pindexPrev->IsValid(BLOCK_VALID_TRANSACTIONS)) {
3939
+ if (pindexPrev->nStatus & BLOCK_FAILED_MASK) {
3940
+ mapBlocksWait.erase(pindexPrev); // prev block was rejected
3941
+ fContinue = true;
3942
+ RemoveBlockRequest(hash);
3943
+ break;
3944
+ }
3945
+ continue; // prev block was not (yet) accepted on disk, skip to next one
3946
+ }
3947
+
3948
+ mapBlocksWait.erase(pindexPrev);
3949
+ fContinue = true;
3950
+ fSelected = true;
3951
+ break;
3952
+ }
3953
+ if (!fSelected)
3954
+ continue;
3955
+
3956
+ const uint256 hash(pblock->GetHash());
3957
+ // Always process the block if we requested it, since we may
3958
+ // need it even when it's not a candidate for a new best tip.
3959
+ forceProcessing = IsBlockRequested(hash);
3960
+ RemoveBlockRequest(hash);
3961
+ // mapBlockSource is only used for punishing peers and setting
3962
+ // which peers send us compact blocks, so the race between here and
3963
+ // cs_main in ProcessNewBlock is fine.
3964
+ mapBlockSource.emplace(hash, std::make_pair(pfrom.GetId(), true));
3965
+ }
3966
+
3967
+ ProcessBlock(pfrom, pblock, forceProcessing);
3968
+ }
3835
3969
  return;
3836
3970
  }
3837
3971
 
@@ -4048,7 +4182,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
4048
4182
  if (pfrom.m_tx_relay != nullptr) {
4049
4183
  pfrom.m_tx_relay->minFeeFilter = newFeeFilter;
4050
4184
  }
4051
- LogPrint(BCLog::NET, "received: feefilter of %s from peer=%d\n", CFeeRate(newFeeFilter).ToString(), pfrom.GetId());
4185
+ LogPrint(BCLog::NET, "received: feefilter of %d satoshi from peer=%d\n", newFeeFilter, pfrom.GetId());
4052
4186
  }
4053
4187
  return;
4054
4188
  }
@@ -4083,7 +4217,6 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
4083
4217
  }
4084
4218
  return;
4085
4219
  }
4086
-
4087
4220
  // Ignore unknown commands for extensibility
4088
4221
  LogPrint(BCLog::NET, "Unknown command \"%s\" from peer=%d\n", SanitizeString(msg_type), pfrom.GetId());
4089
4222
  return;
@@ -4224,13 +4357,13 @@ void PeerManagerImpl::ConsiderEviction(CNode& pto, std::chrono::seconds time_in_
4224
4357
  // their chain has more work than ours, we should sync to it,
4225
4358
  // unless it's invalid, in which case we should find that out and
4226
4359
  // disconnect from them elsewhere).
4227
- if (state.pindexBestKnownBlock != nullptr && state.pindexBestKnownBlock->nChainWork >= m_chainman.ActiveChain().Tip()->nChainWork) {
4360
+ if (state.pindexBestKnownBlock != nullptr && state.pindexBestKnownBlock->nChainTrust >= m_chainman.ActiveChain().Tip()->nChainTrust) {
4228
4361
  if (state.m_chain_sync.m_timeout != 0s) {
4229
4362
  state.m_chain_sync.m_timeout = 0s;
4230
4363
  state.m_chain_sync.m_work_header = nullptr;
4231
4364
  state.m_chain_sync.m_sent_getheaders = false;
4232
4365
  }
4233
- } else if (state.m_chain_sync.m_timeout == 0s || (state.m_chain_sync.m_work_header != nullptr && state.pindexBestKnownBlock != nullptr && state.pindexBestKnownBlock->nChainWork >= state.m_chain_sync.m_work_header->nChainWork)) {
4366
+ } else if (state.m_chain_sync.m_timeout == 0s || (state.m_chain_sync.m_work_header != nullptr && state.pindexBestKnownBlock != nullptr && state.pindexBestKnownBlock->nChainTrust >= state.m_chain_sync.m_work_header->nChainTrust)) {
4234
4367
  // Our best block known by this peer is behind our tip, and we're either noticing
4235
4368
  // that for the first time, OR this peer was able to catch up to some earlier point
4236
4369
  // where we checked against our tip.
@@ -4504,6 +4637,7 @@ void PeerManagerImpl::MaybeSendAddr(CNode& node, Peer& peer, std::chrono::micros
4504
4637
  }
4505
4638
  }
4506
4639
 
4640
+ /*
4507
4641
  void PeerManagerImpl::MaybeSendFeefilter(CNode& pto, std::chrono::microseconds current_time)
4508
4642
  {
4509
4643
  AssertLockHeld(cs_main);
@@ -4546,6 +4680,7 @@ void PeerManagerImpl::MaybeSendFeefilter(CNode& pto, std::chrono::microseconds c
4546
4680
  pto.m_tx_relay->m_next_send_feefilter = current_time + GetRandomDuration<std::chrono::microseconds>(MAX_FEEFILTER_CHANGE_DELAY);
4547
4681
  }
4548
4682
  }
4683
+ */
4549
4684
 
4550
4685
  namespace {
4551
4686
  class CompareInvMempoolOrder
@@ -4833,7 +4968,7 @@ bool PeerManagerImpl::SendMessages(CNode* pto)
4833
4968
  if (fSendTrickle && pto->m_tx_relay->fSendMempool) {
4834
4969
  auto vtxinfo = m_mempool.infoAll();
4835
4970
  pto->m_tx_relay->fSendMempool = false;
4836
- const CFeeRate filterrate{pto->m_tx_relay->minFeeFilter.load()};
4971
+ CAmount filterrate = 0;
4837
4972
 
4838
4973
  LOCK(pto->m_tx_relay->cs_filter);
4839
4974
 
@@ -4841,9 +4976,9 @@ bool PeerManagerImpl::SendMessages(CNode* pto)
4841
4976
  const uint256& hash = state.m_wtxid_relay ? txinfo.tx->GetWitnessHash() : txinfo.tx->GetHash();
4842
4977
  CInv inv(state.m_wtxid_relay ? MSG_WTX : MSG_TX, hash);
4843
4978
  pto->m_tx_relay->setInventoryTxToSend.erase(hash);
4844
- // Don't send transactions that peers will not put into their mempool
4845
- if (txinfo.fee < filterrate.GetFee(txinfo.vsize)) {
4846
- continue;
4979
+ if (filterrate) {
4980
+ if (txinfo.fee < filterrate)
4981
+ continue;
4847
4982
  }
4848
4983
  if (pto->m_tx_relay->pfilter) {
4849
4984
  if (!pto->m_tx_relay->pfilter->IsRelevantAndUpdate(*txinfo.tx)) continue;
@@ -4867,7 +5002,7 @@ bool PeerManagerImpl::SendMessages(CNode* pto)
4867
5002
  for (std::set<uint256>::iterator it = pto->m_tx_relay->setInventoryTxToSend.begin(); it != pto->m_tx_relay->setInventoryTxToSend.end(); it++) {
4868
5003
  vInvTx.push_back(it);
4869
5004
  }
4870
- const CFeeRate filterrate{pto->m_tx_relay->minFeeFilter.load()};
5005
+ CAmount filterrate = 0;
4871
5006
  // Topologically and fee-rate sort the inventory we send for privacy and priority reasons.
4872
5007
  // A heap is used so that not all items need sorting if only a few are being sent.
4873
5008
  CompareInvMempoolOrder compareInvMempoolOrder(&m_mempool, state.m_wtxid_relay);
@@ -4897,7 +5032,7 @@ bool PeerManagerImpl::SendMessages(CNode* pto)
4897
5032
  auto txid = txinfo.tx->GetHash();
4898
5033
  auto wtxid = txinfo.tx->GetWitnessHash();
4899
5034
  // Peer told you to not send transactions at that feerate? Don't bother sending it.
4900
- if (txinfo.fee < filterrate.GetFee(txinfo.vsize)) {
5035
+ if (filterrate && txinfo.fee < filterrate) {
4901
5036
  continue;
4902
5037
  }
4903
5038
  if (pto->m_tx_relay->pfilter && !pto->m_tx_relay->pfilter->IsRelevantAndUpdate(*txinfo.tx)) continue;
@@ -5011,7 +5146,7 @@ bool PeerManagerImpl::SendMessages(CNode* pto)
5011
5146
  NodeId staller = -1;
5012
5147
  FindNextBlocksToDownload(pto->GetId(), MAX_BLOCKS_IN_TRANSIT_PER_PEER - state.nBlocksInFlight, vToDownload, staller);
5013
5148
  for (const CBlockIndex *pindex : vToDownload) {
5014
- uint32_t nFetchFlags = GetFetchFlags(*pto);
5149
+ uint32_t nFetchFlags = IsBTC16BIPsEnabled(pindex->nTime) ? GetFetchFlags(*pto) : false;
5015
5150
  vGetData.push_back(CInv(MSG_BLOCK | nFetchFlags, pindex->GetBlockHash()));
5016
5151
  BlockRequested(pto->GetId(), *pindex);
5017
5152
  LogPrint(BCLog::NET, "Requesting block %s (%d) peer=%d\n", pindex->GetBlockHash().ToString(),
@@ -5051,11 +5186,8 @@ bool PeerManagerImpl::SendMessages(CNode* pto)
5051
5186
  }
5052
5187
  }
5053
5188
 
5054
-
5055
5189
  if (!vGetData.empty())
5056
5190
  m_connman.PushMessage(pto, msgMaker.Make(NetMsgType::GETDATA, vGetData));
5057
-
5058
- MaybeSendFeefilter(*pto, current_time);
5059
5191
  } // release cs_main
5060
5192
  return true;
5061
5193
  }
src/netmessagemaker.h CHANGED
@@ -19,7 +19,7 @@ public:
19
19
  {
20
20
  CSerializedNetMsg msg;
21
21
  msg.m_type = std::move(msg_type);
22
- CVectorWriter{ SER_NETWORK, nFlags | nVersion, msg.data, 0, std::forward<Args>(args)... };
22
+ CVectorWriter{ SER_NETWORK | SER_POSMARKER, nFlags | nVersion, msg.data, 0, std::forward<Args>(args)... };
23
23
  return msg;
24
24
  }
25
25
 
src/node/blockstorage.cpp CHANGED
@@ -11,6 +11,7 @@
11
11
  #include <flatfile.h>
12
12
  #include <fs.h>
13
13
  #include <hash.h>
14
+ #include <kernel.h>
14
15
  #include <pow.h>
15
16
  #include <reverse_iterator.h>
16
17
  #include <shutdown.h>
@@ -24,9 +25,6 @@
24
25
  namespace node {
25
26
  std::atomic_bool fImporting(false);
26
27
  std::atomic_bool fReindex(false);
27
- bool fHavePruned = false;
28
- bool fPruneMode = false;
29
- uint64_t nPruneTarget = 0;
30
28
 
31
29
  static FILE* OpenUndoFile(const FlatFilePos& pos, bool fReadOnly = false);
32
30
  static FlatFileSeq BlockFileSeq();
@@ -65,9 +63,11 @@ CBlockIndex* BlockManager::AddToBlockIndex(const CBlockHeader& block)
65
63
  pindexNew->BuildSkip();
66
64
  }
67
65
  pindexNew->nTimeMax = (pindexNew->pprev ? std::max(pindexNew->pprev->nTimeMax, pindexNew->nTime) : pindexNew->nTime);
68
- pindexNew->nChainWork = (pindexNew->pprev ? pindexNew->pprev->nChainWork : 0) + GetBlockProof(*pindexNew);
66
+ if (block.nFlags & CBlockIndex::BLOCK_PROOF_OF_STAKE)
67
+ pindexNew->SetProofOfStake();
68
+ pindexNew->nChainTrust = (pindexNew->pprev ? pindexNew->pprev->nChainTrust : 0) + GetBlockTrust(*pindexNew);
69
69
  pindexNew->RaiseValidity(BLOCK_VALID_TREE);
70
- if (pindexBestHeader == nullptr || pindexBestHeader->nChainWork < pindexNew->nChainWork)
70
+ if (pindexBestHeader == nullptr || pindexBestHeader->nChainTrust < pindexNew->nChainTrust)
71
71
  pindexBestHeader = pindexNew;
72
72
 
73
73
  m_dirty_blockindex.insert(pindexNew);
@@ -75,122 +75,6 @@ CBlockIndex* BlockManager::AddToBlockIndex(const CBlockHeader& block)
75
75
  return pindexNew;
76
76
  }
77
77
 
78
- void BlockManager::PruneOneBlockFile(const int fileNumber)
79
- {
80
- AssertLockHeld(cs_main);
81
- LOCK(cs_LastBlockFile);
82
-
83
- for (const auto& entry : m_block_index) {
84
- CBlockIndex* pindex = entry.second;
85
- if (pindex->nFile == fileNumber) {
86
- pindex->nStatus &= ~BLOCK_HAVE_DATA;
87
- pindex->nStatus &= ~BLOCK_HAVE_UNDO;
88
- pindex->nFile = 0;
89
- pindex->nDataPos = 0;
90
- pindex->nUndoPos = 0;
91
- m_dirty_blockindex.insert(pindex);
92
-
93
- // Prune from m_blocks_unlinked -- any block we prune would have
94
- // to be downloaded again in order to consider its chain, at which
95
- // point it would be considered as a candidate for
96
- // m_blocks_unlinked or setBlockIndexCandidates.
97
- auto range = m_blocks_unlinked.equal_range(pindex->pprev);
98
- while (range.first != range.second) {
99
- std::multimap<CBlockIndex*, CBlockIndex*>::iterator _it = range.first;
100
- range.first++;
101
- if (_it->second == pindex) {
102
- m_blocks_unlinked.erase(_it);
103
- }
104
- }
105
- }
106
- }
107
-
108
- m_blockfile_info[fileNumber].SetNull();
109
- m_dirty_fileinfo.insert(fileNumber);
110
- }
111
-
112
- void BlockManager::FindFilesToPruneManual(std::set<int>& setFilesToPrune, int nManualPruneHeight, int chain_tip_height)
113
- {
114
- assert(fPruneMode && nManualPruneHeight > 0);
115
-
116
- LOCK2(cs_main, cs_LastBlockFile);
117
- if (chain_tip_height < 0) {
118
- return;
119
- }
120
-
121
- // last block to prune is the lesser of (user-specified height, MIN_BLOCKS_TO_KEEP from the tip)
122
- unsigned int nLastBlockWeCanPrune = std::min((unsigned)nManualPruneHeight, chain_tip_height - MIN_BLOCKS_TO_KEEP);
123
- int count = 0;
124
- for (int fileNumber = 0; fileNumber < m_last_blockfile; fileNumber++) {
125
- if (m_blockfile_info[fileNumber].nSize == 0 || m_blockfile_info[fileNumber].nHeightLast > nLastBlockWeCanPrune) {
126
- continue;
127
- }
128
- PruneOneBlockFile(fileNumber);
129
- setFilesToPrune.insert(fileNumber);
130
- count++;
131
- }
132
- LogPrintf("Prune (Manual): prune_height=%d removed %d blk/rev pairs\n", nLastBlockWeCanPrune, count);
133
- }
134
-
135
- void BlockManager::FindFilesToPrune(std::set<int>& setFilesToPrune, uint64_t nPruneAfterHeight, int chain_tip_height, int prune_height, bool is_ibd)
136
- {
137
- LOCK2(cs_main, cs_LastBlockFile);
138
- if (chain_tip_height < 0 || nPruneTarget == 0) {
139
- return;
140
- }
141
- if ((uint64_t)chain_tip_height <= nPruneAfterHeight) {
142
- return;
143
- }
144
-
145
- unsigned int nLastBlockWeCanPrune{(unsigned)std::min(prune_height, chain_tip_height - static_cast<int>(MIN_BLOCKS_TO_KEEP))};
146
- uint64_t nCurrentUsage = CalculateCurrentUsage();
147
- // We don't check to prune until after we've allocated new space for files
148
- // So we should leave a buffer under our target to account for another allocation
149
- // before the next pruning.
150
- uint64_t nBuffer = BLOCKFILE_CHUNK_SIZE + UNDOFILE_CHUNK_SIZE;
151
- uint64_t nBytesToPrune;
152
- int count = 0;
153
-
154
- if (nCurrentUsage + nBuffer >= nPruneTarget) {
155
- // On a prune event, the chainstate DB is flushed.
156
- // To avoid excessive prune events negating the benefit of high dbcache
157
- // values, we should not prune too rapidly.
158
- // So when pruning in IBD, increase the buffer a bit to avoid a re-prune too soon.
159
- if (is_ibd) {
160
- // Since this is only relevant during IBD, we use a fixed 10%
161
- nBuffer += nPruneTarget / 10;
162
- }
163
-
164
- for (int fileNumber = 0; fileNumber < m_last_blockfile; fileNumber++) {
165
- nBytesToPrune = m_blockfile_info[fileNumber].nSize + m_blockfile_info[fileNumber].nUndoSize;
166
-
167
- if (m_blockfile_info[fileNumber].nSize == 0) {
168
- continue;
169
- }
170
-
171
- if (nCurrentUsage + nBuffer < nPruneTarget) { // are we below our target?
172
- break;
173
- }
174
-
175
- // don't prune files that could have a block within MIN_BLOCKS_TO_KEEP of the main chain's tip but keep scanning
176
- if (m_blockfile_info[fileNumber].nHeightLast > nLastBlockWeCanPrune) {
177
- continue;
178
- }
179
-
180
- PruneOneBlockFile(fileNumber);
181
- // Queue up the files for removal
182
- setFilesToPrune.insert(fileNumber);
183
- nCurrentUsage -= nBytesToPrune;
184
- count++;
185
- }
186
- }
187
-
188
- LogPrint(BCLog::PRUNE, "Prune: target=%dMiB actual=%dMiB diff=%dMiB max_prune_height=%d removed %d blk/rev pairs\n",
189
- nPruneTarget/1024/1024, nCurrentUsage/1024/1024,
190
- ((int64_t)nPruneTarget - (int64_t)nCurrentUsage)/1024/1024,
191
- nLastBlockWeCanPrune, count);
192
- }
193
-
194
78
  CBlockIndex* BlockManager::InsertBlockIndex(const uint256& hash)
195
79
  {
196
80
  AssertLockHeld(cs_main);
@@ -221,7 +105,7 @@ bool BlockManager::LoadBlockIndex(
221
105
  return false;
222
106
  }
223
107
 
224
- // Calculate nChainWork
108
+ // Calculate nChainTrust
225
109
  std::vector<std::pair<int, CBlockIndex*>> vSortedByHeight;
226
110
  vSortedByHeight.reserve(m_block_index.size());
227
111
  for (const std::pair<const uint256, CBlockIndex*>& item : m_block_index) {
@@ -253,13 +137,12 @@ bool BlockManager::LoadBlockIndex(
253
137
  for (const std::pair<int, CBlockIndex*>& item : vSortedByHeight) {
254
138
  if (ShutdownRequested()) return false;
255
139
  CBlockIndex* pindex = item.second;
256
- pindex->nChainWork = (pindex->pprev ? pindex->pprev->nChainWork : 0) + GetBlockProof(*pindex);
140
+ pindex->nChainTrust = (pindex->pprev ? pindex->pprev->nChainTrust : 0) + GetBlockTrust(*pindex);
257
141
  pindex->nTimeMax = (pindex->pprev ? std::max(pindex->pprev->nTimeMax, pindex->nTime) : pindex->nTime);
258
142
 
259
143
  // We can link the chain of blocks for which we've received transactions at some point, or
260
144
  // blocks that are assumed-valid on the basis of snapshot load (see
261
145
  // PopulateAndValidateSnapshot()).
262
- // Pruned nodes may have deleted the block.
263
146
  if (pindex->nTx > 0) {
264
147
  if (pindex->pprev) {
265
148
  if (pindex->pprev->nChainTx > 0) {
@@ -310,7 +193,7 @@ bool BlockManager::LoadBlockIndex(
310
193
  }
311
194
  }
312
195
  }
313
- if (pindex->nStatus & BLOCK_FAILED_MASK && (!chainman.m_best_invalid || pindex->nChainWork > chainman.m_best_invalid->nChainWork)) {
196
+ if (pindex->nStatus & BLOCK_FAILED_MASK && (!chainman.m_best_invalid || pindex->nChainTrust > chainman.m_best_invalid->nChainTrust)) {
314
197
  chainman.m_best_invalid = pindex;
315
198
  }
316
199
  if (pindex->pprev) {
@@ -318,6 +201,12 @@ bool BlockManager::LoadBlockIndex(
318
201
  }
319
202
  if (pindex->IsValid(BLOCK_VALID_TREE) && (pindexBestHeader == nullptr || CBlockIndexWorkComparator()(pindexBestHeader, pindex)))
320
203
  pindexBestHeader = pindex;
204
+
205
+ // peercoin: calculate stake modifier checksum
206
+ pindex->nStakeModifierChecksum = GetStakeModifierChecksum(pindex);
207
+ if (chainman.ActiveChain().Contains(pindex))
208
+ if (!CheckStakeModifierCheckpoints(pindex->nHeight, pindex->nStakeModifierChecksum))
209
+ return error("LoadBlockIndex() : Failed stake modifier checkpoint height=%d, modifier=0x%016llx", pindex->nHeight, pindex->nStakeModifier);
321
210
  }
322
211
 
323
212
  return true;
@@ -399,12 +288,6 @@ bool BlockManager::LoadBlockIndexDB(ChainstateManager& chainman)
399
288
  }
400
289
  }
401
290
 
402
- // Check whether we have ever pruned block & undo files
403
- m_block_tree_db->ReadFlag("prunedblockfiles", fHavePruned);
404
- if (fHavePruned) {
405
- LogPrintf("LoadBlockIndexDB(): Block files have previously been pruned\n");
406
- }
407
-
408
291
  // Check whether we need to continue reindexing
409
292
  bool fReindexing = false;
410
293
  m_block_tree_db->ReadReindexing(fReindexing);
@@ -427,55 +310,6 @@ CBlockIndex* BlockManager::GetLastCheckpoint(const CCheckpointData& data)
427
310
  return nullptr;
428
311
  }
429
312
 
430
- bool IsBlockPruned(const CBlockIndex* pblockindex)
431
- {
432
- AssertLockHeld(::cs_main);
433
- return (fHavePruned && !(pblockindex->nStatus & BLOCK_HAVE_DATA) && pblockindex->nTx > 0);
434
- }
435
-
436
- // If we're using -prune with -reindex, then delete block files that will be ignored by the
437
- // reindex. Since reindexing works by starting at block file 0 and looping until a blockfile
438
- // is missing, do the same here to delete any later block files after a gap. Also delete all
439
- // rev files since they'll be rewritten by the reindex anyway. This ensures that m_blockfile_info
440
- // is in sync with what's actually on disk by the time we start downloading, so that pruning
441
- // works correctly.
442
- void CleanupBlockRevFiles()
443
- {
444
- std::map<std::string, fs::path> mapBlockFiles;
445
-
446
- // Glob all blk?????.dat and rev?????.dat files from the blocks directory.
447
- // Remove the rev files immediately and insert the blk file paths into an
448
- // ordered map keyed by block file index.
449
- LogPrintf("Removing unusable blk?????.dat and rev?????.dat files for -reindex with -prune\n");
450
- fs::path blocksdir = gArgs.GetBlocksDirPath();
451
- for (fs::directory_iterator it(blocksdir); it != fs::directory_iterator(); it++) {
452
- const std::string path = fs::PathToString(it->path().filename());
453
- if (fs::is_regular_file(*it) &&
454
- path.length() == 12 &&
455
- path.substr(8,4) == ".dat")
456
- {
457
- if (path.substr(0, 3) == "blk") {
458
- mapBlockFiles[path.substr(3, 5)] = it->path();
459
- } else if (path.substr(0, 3) == "rev") {
460
- remove(it->path());
461
- }
462
- }
463
- }
464
-
465
- // Remove all block files that aren't part of a contiguous set starting at
466
- // zero by walking the ordered map (keys are block file indices) by
467
- // keeping a separate counter. Once we hit a gap (or if 0 doesn't exist)
468
- // start removing block files.
469
- int nContigCounter = 0;
470
- for (const std::pair<const std::string, fs::path>& item : mapBlockFiles) {
471
- if (LocaleIndependentAtoi<int>(item.first) == nContigCounter) {
472
- nContigCounter++;
473
- continue;
474
- }
475
- remove(item.second);
476
- }
477
- }
478
-
479
313
  CBlockFileInfo* BlockManager::GetBlockFileInfo(size_t n)
480
314
  {
481
315
  LOCK(cs_LastBlockFile);
@@ -576,16 +410,6 @@ uint64_t BlockManager::CalculateCurrentUsage()
576
410
  return retval;
577
411
  }
578
412
 
579
- void UnlinkPrunedFiles(const std::set<int>& setFilesToPrune)
580
- {
581
- for (std::set<int>::iterator it = setFilesToPrune.begin(); it != setFilesToPrune.end(); ++it) {
582
- FlatFilePos pos(*it, 0);
583
- fs::remove(BlockFileSeq().FileName(pos));
584
- fs::remove(UndoFileSeq().FileName(pos));
585
- LogPrint(BCLog::BLOCKSTORE, "Prune: %s deleted blk/rev (%05u)\n", __func__, *it);
586
- }
587
- }
588
-
589
413
  static FlatFileSeq BlockFileSeq()
590
414
  {
591
415
  return FlatFileSeq(gArgs.GetBlocksDirPath(), "blk", gArgs.GetBoolArg("-fastprune", false) ? 0x4000 /* 16kb */ : BLOCKFILE_CHUNK_SIZE);
@@ -658,9 +482,6 @@ bool BlockManager::FindBlockPos(FlatFilePos& pos, unsigned int nAddSize, unsigne
658
482
  if (out_of_space) {
659
483
  return AbortNode("Disk space is too low!", _("Disk space is too low!"));
660
484
  }
661
- if (bytes_allocated != 0 && fPruneMode) {
662
- m_check_for_pruning = true;
663
- }
664
485
  }
665
486
 
666
487
  m_dirty_fileinfo.insert(nFile);
@@ -682,9 +503,6 @@ bool BlockManager::FindUndoPos(BlockValidationState& state, int nFile, FlatFileP
682
503
  if (out_of_space) {
683
504
  return AbortNode(state, "Disk space is too low!", _("Disk space is too low!"));
684
505
  }
685
- if (bytes_allocated != 0 && fPruneMode) {
686
- m_check_for_pruning = true;
687
- }
688
506
 
689
507
  return true;
690
508
  }
@@ -760,7 +578,7 @@ bool ReadBlockFromDisk(CBlock& block, const FlatFilePos& pos, const Consensus::P
760
578
  }
761
579
 
762
580
  // Check the header
763
- if (!CheckProofOfWork(block.GetHash(), block.nBits, consensusParams)) {
581
+ if (block.IsProofOfWork() && !CheckProofOfWork(block.GetHash(), block.nBits, consensusParams)) {
764
582
  return error("ReadBlockFromDisk: Errors in block header at %s", pos.ToString());
765
583
  }
766
584
 
@@ -769,6 +587,10 @@ bool ReadBlockFromDisk(CBlock& block, const FlatFilePos& pos, const Consensus::P
769
587
  return error("ReadBlockFromDisk: Errors in block solution at %s", pos.ToString());
770
588
  }
771
589
 
590
+ // Set flag if proof of stake
591
+ if (block.IsProofOfStake())
592
+ block.nFlags |= CBlockIndex::BLOCK_PROOF_OF_STAKE;
593
+
772
594
  return true;
773
595
  }
774
596
 
src/node/blockstorage.h CHANGED
@@ -44,13 +44,6 @@ static const unsigned int MAX_BLOCKFILE_SIZE = 0x8000000; // 128 MiB
44
44
 
45
45
  extern std::atomic_bool fImporting;
46
46
  extern std::atomic_bool fReindex;
47
- /** Pruning-related variables and constants */
48
- /** True if any block files have ever been pruned. */
49
- extern bool fHavePruned;
50
- /** True if we're running in -prune mode. */
51
- extern bool fPruneMode;
52
- /** Number of MiB of block files that we're trying to stay below. */
53
- extern uint64_t nPruneTarget;
54
47
 
55
48
  typedef std::unordered_map<uint256, CBlockIndex*, BlockHasher> BlockMap;
56
49
 
@@ -76,37 +69,9 @@ private:
76
69
  bool FindBlockPos(FlatFilePos& pos, unsigned int nAddSize, unsigned int nHeight, CChain& active_chain, uint64_t nTime, bool fKnown);
77
70
  bool FindUndoPos(BlockValidationState& state, int nFile, FlatFilePos& pos, unsigned int nAddSize);
78
71
 
79
- /* Calculate the block/rev files to delete based on height specified by user with RPC command pruneblockchain */
80
- void FindFilesToPruneManual(std::set<int>& setFilesToPrune, int nManualPruneHeight, int chain_tip_height);
81
-
82
- /**
83
- * Prune block and undo files (blk???.dat and rev???.dat) so that the disk space used is less than a user-defined target.
84
- * The user sets the target (in MB) on the command line or in config file. This will be run on startup and whenever new
85
- * space is allocated in a block or undo file, staying below the target. Changing back to unpruned requires a reindex
86
- * (which in this case means the blockchain must be re-downloaded.)
87
- *
88
- * Pruning functions are called from FlushStateToDisk when the m_check_for_pruning flag has been set.
89
- * Block and undo files are deleted in lock-step (when blk00003.dat is deleted, so is rev00003.dat.)
90
- * Pruning cannot take place until the longest chain is at least a certain length (CChainParams::nPruneAfterHeight).
91
- * Pruning will never delete a block within a defined distance (currently 288) from the active chain's tip.
92
- * The block index is updated by unsetting HAVE_DATA and HAVE_UNDO for any blocks that were stored in the deleted files.
93
- * A db flag records the fact that at least some block files have been pruned.
94
- *
95
- * @param[out] setFilesToPrune The set of file indices that can be unlinked will be returned
96
- */
97
- void FindFilesToPrune(std::set<int>& setFilesToPrune, uint64_t nPruneAfterHeight, int chain_tip_height, int prune_height, bool is_ibd);
98
-
99
72
  RecursiveMutex cs_LastBlockFile;
100
73
  std::vector<CBlockFileInfo> m_blockfile_info;
101
74
  int m_last_blockfile = 0;
102
- /** Global flag to indicate we should check to see if there are
103
- * block/undo files that should be deleted. Set on startup
104
- * or if we allocate more file space when we're in prune mode
105
- */
106
- bool m_check_for_pruning = false;
107
-
108
- /** Dirty block index entries. */
109
- std::set<CBlockIndex*> m_dirty_blockindex;
110
75
 
111
76
  /** Dirty block file entries. */
112
77
  std::set<int> m_dirty_fileinfo;
@@ -116,12 +81,13 @@ public:
116
81
 
117
82
  /**
118
83
  * All pairs A->B, where A (or one of its ancestors) misses transactions, but B has transactions.
119
- * Pruned nodes may have entries where B is missing data.
120
84
  */
121
85
  std::multimap<CBlockIndex*, CBlockIndex*> m_blocks_unlinked;
122
-
123
86
  std::unique_ptr<CBlockTreeDB> m_block_tree_db GUARDED_BY(::cs_main);
124
87
 
88
+ /** Dirty block index entries. */
89
+ std::set<CBlockIndex*> m_dirty_blockindex;
90
+
125
91
  bool WriteBlockIndexDB() EXCLUSIVE_LOCKS_REQUIRED(::cs_main);
126
92
  bool LoadBlockIndexDB(ChainstateManager& chainman) EXCLUSIVE_LOCKS_REQUIRED(::cs_main);
127
93
 
@@ -141,9 +107,6 @@ public:
141
107
  /** Create a new block index entry for a given block hash */
142
108
  CBlockIndex* InsertBlockIndex(const uint256& hash) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
143
109
 
144
- //! Mark one block file as pruned (modify associated database entries)
145
- void PruneOneBlockFile(const int fileNumber) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
146
-
147
110
  CBlockIndex* LookupBlockIndex(const uint256& hash) const EXCLUSIVE_LOCKS_REQUIRED(cs_main);
148
111
 
149
112
  /** Get block file info entry for one block file */
@@ -166,21 +129,11 @@ public:
166
129
  }
167
130
  };
168
131
 
169
- //! Check whether the block associated with this index entry is pruned or not.
170
- bool IsBlockPruned(const CBlockIndex* pblockindex) EXCLUSIVE_LOCKS_REQUIRED(::cs_main);
171
-
172
- void CleanupBlockRevFiles();
173
-
174
132
  /** Open a block file (blk?????.dat) */
175
133
  FILE* OpenBlockFile(const FlatFilePos& pos, bool fReadOnly = false);
176
134
  /** Translation to a filesystem path */
177
135
  fs::path GetBlockPosFilename(const FlatFilePos& pos);
178
136
 
179
- /**
180
- * Actually unlink the specified files
181
- */
182
- void UnlinkPrunedFiles(const std::set<int>& setFilesToPrune);
183
-
184
137
  /** Functions for disk access for blocks */
185
138
  bool ReadBlockFromDisk(CBlock& block, const FlatFilePos& pos, const Consensus::Params& consensusParams);
186
139
  bool ReadBlockFromDisk(CBlock& block, const CBlockIndex* pindex, const Consensus::Params& consensusParams);
src/node/chainstate.cpp CHANGED
@@ -12,7 +12,6 @@ namespace node {
12
12
  std::optional<ChainstateLoadingError> LoadChainstate(bool fReset,
13
13
  ChainstateManager& chainman,
14
14
  CTxMemPool* mempool,
15
- bool fPruneMode,
16
15
  const Consensus::Params& consensus_params,
17
16
  bool fReindexChainState,
18
17
  int64_t nBlockTreeDBCache,
@@ -42,16 +41,11 @@ std::optional<ChainstateLoadingError> LoadChainstate(bool fReset,
42
41
 
43
42
  if (fReset) {
44
43
  pblocktree->WriteReindexing(true);
45
- //If we're reindexing in prune mode, wipe away unusable block files and all undo data files
46
- if (fPruneMode)
47
- CleanupBlockRevFiles();
48
44
  }
49
45
 
50
46
  if (shutdown_requested && shutdown_requested()) return ChainstateLoadingError::SHUTDOWN_PROBED;
51
47
 
52
- // LoadBlockIndex will load fHavePruned if we've ever removed a
53
- // block file from disk.
54
- // Note that it also sets fReindex based on the disk flag!
48
+ // Note that LoadBlockIndex also sets fReindex based on the disk flag!
55
49
  // From here on out fReindex and fReset mean something different!
56
50
  if (!chainman.LoadBlockIndex()) {
57
51
  if (shutdown_requested && shutdown_requested()) return ChainstateLoadingError::SHUTDOWN_PROBED;
@@ -63,12 +57,6 @@ std::optional<ChainstateLoadingError> LoadChainstate(bool fReset,
63
57
  return ChainstateLoadingError::ERROR_BAD_GENESIS_BLOCK;
64
58
  }
65
59
 
66
- // Check for changed -prune state. What we are concerned about is a user who has pruned blocks
67
- // in the past, but is now trying to run unpruned.
68
- if (fHavePruned && !fPruneMode) {
69
- return ChainstateLoadingError::ERROR_PRUNED_NEEDS_REINDEX;
70
- }
71
-
72
60
  // At this point blocktree args are consistent with what's on disk.
73
61
  // If we're not mid-reindex (based on disk + args), add a genesis block on disk
74
62
  // (otherwise we use the one already on disk).
src/node/chainstate.h CHANGED
@@ -19,7 +19,6 @@ namespace node {
19
19
  enum class ChainstateLoadingError {
20
20
  ERROR_LOADING_BLOCK_DB,
21
21
  ERROR_BAD_GENESIS_BLOCK,
22
- ERROR_PRUNED_NEEDS_REINDEX,
23
22
  ERROR_LOAD_GENESIS_BLOCK_FAILED,
24
23
  ERROR_CHAINSTATE_UPGRADE_FAILED,
25
24
  ERROR_REPLAYBLOCKS_FAILED,
@@ -58,7 +57,6 @@ enum class ChainstateLoadingError {
58
57
  std::optional<ChainstateLoadingError> LoadChainstate(bool fReset,
59
58
  ChainstateManager& chainman,
60
59
  CTxMemPool* mempool,
61
- bool fPruneMode,
62
60
  const Consensus::Params& consensus_params,
63
61
  bool fReindexChainState,
64
62
  int64_t nBlockTreeDBCache,
src/node/context.cpp CHANGED
@@ -9,7 +9,6 @@
9
9
  #include <interfaces/chain.h>
10
10
  #include <net.h>
11
11
  #include <net_processing.h>
12
- #include <policy/fees.h>
13
12
  #include <scheduler.h>
14
13
  #include <txmempool.h>
15
14
  #include <validation.h>
src/node/context.h CHANGED
@@ -10,21 +10,23 @@
10
10
  #include <memory>
11
11
  #include <vector>
12
12
 
13
+ #include <interfaces/init.h>
14
+ #include <interfaces/chain.h>
15
+ #include <interfaces/wallet.h>
16
+
13
17
  class ArgsManager;
14
18
  class BanMan;
15
19
  class AddrMan;
16
- class CBlockPolicyEstimator;
17
20
  class CConnman;
18
21
  class CScheduler;
19
22
  class CTxMemPool;
20
23
  class ChainstateManager;
21
24
  class PeerManager;
22
- namespace interfaces {
23
- class Chain;
24
- class ChainClient;
25
- class Init;
26
- class WalletLoader;
27
- } // namespace interfaces
25
+
26
+ using interfaces::Chain;
27
+ using interfaces::ChainClient;
28
+ using interfaces::Init;
29
+ using interfaces::WalletLoader;
28
30
 
29
31
  namespace node {
30
32
  //! NodeContext struct containing references to chain state and connection
@@ -43,7 +45,6 @@ struct NodeContext {
43
45
  std::unique_ptr<AddrMan> addrman;
44
46
  std::unique_ptr<CConnman> connman;
45
47
  std::unique_ptr<CTxMemPool> mempool;
46
- std::unique_ptr<CBlockPolicyEstimator> fee_estimator;
47
48
  std::unique_ptr<PeerManager> peerman;
48
49
  std::unique_ptr<ChainstateManager> chainman;
49
50
  std::unique_ptr<BanMan> banman;
src/node/interfaces.cpp CHANGED
@@ -6,7 +6,6 @@
6
6
  #include <banman.h>
7
7
  #include <chain.h>
8
8
  #include <chainparams.h>
9
- #include <deploymentstatus.h>
10
9
  #include <external_signer.h>
11
10
  #include <init.h>
12
11
  #include <interfaces/chain.h>
@@ -23,10 +22,7 @@
23
22
  #include <node/context.h>
24
23
  #include <node/transaction.h>
25
24
  #include <node/ui_interface.h>
26
- #include <policy/feerate.h>
27
- #include <policy/fees.h>
28
25
  #include <policy/policy.h>
29
- #include <policy/rbf.h>
30
26
  #include <policy/settings.h>
31
27
  #include <primitives/block.h>
32
28
  #include <primitives/transaction.h>
@@ -81,8 +77,8 @@ private:
81
77
  class NodeImpl : public Node
82
78
  {
83
79
  private:
84
- ChainstateManager& chainman() { return *Assert(m_context->chainman); }
85
80
  public:
81
+ ChainstateManager& chainman() override { return *Assert(m_context->chainman); }
86
82
  explicit NodeImpl(NodeContext& context) { setContext(&context); }
87
83
  void initLogging() override { InitLogging(*Assert(m_context->args)); }
88
84
  void initParameterInteraction() override { InitParameterInteraction(*Assert(m_context->args)); }
@@ -258,7 +254,6 @@ public:
258
254
  }
259
255
  }
260
256
  bool getNetworkActive() override { return m_context->connman && m_context->connman->GetNetworkActive(); }
261
- CFeeRate getDustRelayFee() override { return ::dustRelayFee; }
262
257
  UniValue executeRpc(const std::string& command, const UniValue& params, const std::string& uri) override
263
258
  {
264
259
  JSONRPCRequest req;
@@ -276,9 +271,9 @@ public:
276
271
  LOCK(::cs_main);
277
272
  return chainman().ActiveChainstate().CoinsTip().GetCoin(output, coin);
278
273
  }
279
- TransactionError broadcastTransaction(CTransactionRef tx, CAmount max_tx_fee, std::string& err_string) override
274
+ TransactionError broadcastTransaction(CTransactionRef tx, std::string& err_string) override
280
275
  {
281
- return BroadcastTransaction(*m_context, std::move(tx), err_string, max_tx_fee, /*relay=*/ true, /*wait_callback=*/ false);
276
+ return BroadcastTransaction(*m_context, std::move(tx), err_string, /*relay=*/ true, /*wait_callback=*/ false);
282
277
  }
283
278
  WalletLoader& walletLoader() override
284
279
  {
@@ -314,7 +309,9 @@ public:
314
309
  }
315
310
  std::unique_ptr<Handler> handleNotifyAlertChanged(NotifyAlertChangedFn fn) override
316
311
  {
317
- return MakeHandler(::uiInterface.NotifyAlertChanged_connect(fn));
312
+ return MakeHandler(::uiInterface.NotifyAlertChanged_connect([fn](const uint256 &hash, ChangeType status) {
313
+ fn(hash, status);
314
+ }));
318
315
  }
319
316
  std::unique_ptr<Handler> handleBannedListChanged(BannedListChangedFn fn) override
320
317
  {
@@ -452,8 +449,8 @@ public:
452
449
  class ChainImpl : public Chain
453
450
  {
454
451
  private:
455
- ChainstateManager& chainman() { return *Assert(m_node.chainman); }
456
452
  public:
453
+ ChainstateManager& chainman() override { return *Assert(m_node.chainman); }
457
454
  explicit ChainImpl(NodeContext& node) : m_node(node) {}
458
455
  std::optional<int> getHeight() override
459
456
  {
@@ -550,7 +547,7 @@ public:
550
547
  bool hasBlocks(const uint256& block_hash, int min_height, std::optional<int> max_height) override
551
548
  {
552
549
  // hasBlocks returns true if all ancestors of block_hash in specified
553
- // range have block data (are not pruned), false if any ancestors in
550
+ // range have block data, false if any ancestors in
554
551
  // specified range are missing data.
555
552
  //
556
553
  // For simplicity and robustness, min_height and max_height are only
@@ -566,12 +563,14 @@ public:
566
563
  }
567
564
  return false;
568
565
  }
566
+ /*
569
567
  RBFTransactionState isRBFOptIn(const CTransaction& tx) override
570
568
  {
571
569
  if (!m_node.mempool) return IsRBFOptInEmptyMempool(tx);
572
570
  LOCK(m_node.mempool->cs);
573
571
  return IsRBFOptIn(tx, *m_node.mempool);
574
572
  }
573
+ */
575
574
  bool isInMempool(const uint256& txid) override
576
575
  {
577
576
  if (!m_node.mempool) return false;
@@ -586,11 +585,10 @@ public:
586
585
  return it && (*it)->GetCountWithDescendants() > 1;
587
586
  }
588
587
  bool broadcastTransaction(const CTransactionRef& tx,
589
- const CAmount& max_tx_fee,
590
588
  bool relay,
591
589
  std::string& err_string) override
592
590
  {
593
- const TransactionError err = BroadcastTransaction(m_node, tx, err_string, max_tx_fee, relay, /*wait_callback*/ false);
591
+ const TransactionError err = BroadcastTransaction(m_node, tx, err_string, relay, /*wait_callback*/ false);
594
592
  // Chain clients only care about failures to accept the tx to the mempool. Disregard non-mempool related failures.
595
593
  // Note: this will need to be updated if BroadcastTransactions() is updated to return other non-mempool failures
596
594
  // that Chain clients do not need to know about.
@@ -623,6 +621,7 @@ public:
623
621
  entry, ancestors, limit_ancestor_count, limit_ancestor_size,
624
622
  limit_descendant_count, limit_descendant_size, unused_error_string);
625
623
  }
624
+ /*
626
625
  CFeeRate estimateSmartFee(int num_blocks, bool conservative, FeeCalculation* calc) override
627
626
  {
628
627
  if (!m_node.fee_estimator) return {};
@@ -641,11 +640,7 @@ public:
641
640
  CFeeRate relayMinFee() override { return ::minRelayTxFee; }
642
641
  CFeeRate relayIncrementalFee() override { return ::incrementalRelayFee; }
643
642
  CFeeRate relayDustFee() override { return ::dustRelayFee; }
644
- bool havePruned() override
645
- {
646
- LOCK(cs_main);
647
- return node::fHavePruned;
648
- }
643
+ */
649
644
  bool isReadyToBroadcast() override { return !node::fImporting && !node::fReindex && !isInitialBlockDownload(); }
650
645
  bool isInitialBlockDownload() override {
651
646
  return chainman().ActiveChainstate().IsInitialBlockDownload();
src/node/miner.cpp CHANGED
@@ -13,34 +13,53 @@
13
13
  #include <consensus/merkle.h>
14
14
  #include <consensus/tx_verify.h>
15
15
  #include <consensus/validation.h>
16
- #include <deploymentstatus.h>
17
- #include <policy/feerate.h>
18
16
  #include <policy/policy.h>
19
17
  #include <pow.h>
20
18
  #include <primitives/transaction.h>
19
+ #include <rpc/blockchain.h>
21
20
  #include <timedata.h>
21
+ #include <rpc/blockchain.h>
22
22
  #include <util/moneystr.h>
23
23
  #include <util/system.h>
24
+ #include <util/threadnames.h>
25
+ #include <util/translation.h>
24
26
  #include <validation.h>
27
+ #include <kernel.h>
28
+ #include <net.h>
29
+ #include <interfaces/chain.h>
30
+ #include <node/context.h>
31
+ #include <node/ui_interface.h>
32
+ #include <util/thread.h>
33
+ #include <validation.h>
34
+ #include <wallet/wallet.h>
35
+ #include <wallet/coincontrol.h>
36
+ #include <warnings.h>
37
+ #include <wallet/spend.h>
38
+ #include <wallet/wallet.h>
25
39
 
26
40
  #include <algorithm>
27
41
  #include <utility>
28
42
 
43
+ #include <boost/thread.hpp>
44
+
45
+ using wallet::CWallet;
46
+ using wallet::COutput;
47
+ using wallet::CCoinControl;
48
+ using wallet::ReserveDestination;
49
+
50
+ int64_t nLastCoinStakeSearchInterval = 0;
51
+ std::thread m_minter_thread;
52
+
29
53
  namespace node {
30
- int64_t UpdateTime(CBlockHeader* pblock, const Consensus::Params& consensusParams, const CBlockIndex* pindexPrev)
54
+ int64_t UpdateTime(CBlockHeader* pblock)
31
55
  {
32
56
  int64_t nOldTime = pblock->nTime;
33
- int64_t nNewTime = std::max(pindexPrev->GetMedianTimePast() + 1, GetAdjustedTime());
57
+ int64_t nNewTime = std::max(pblock->GetBlockTime(), GetAdjustedTime());
34
58
 
35
59
  if (nOldTime < nNewTime) {
36
60
  pblock->nTime = nNewTime;
37
61
  }
38
62
 
39
- // Updating time can change work required on testnet:
40
- if (consensusParams.fPowAllowMinDifficultyBlocks) {
41
- pblock->nBits = GetNextWorkRequired(pindexPrev, pblock, consensusParams);
42
- }
43
-
44
63
  return nNewTime - nOldTime;
45
64
  }
46
65
 
@@ -58,7 +77,6 @@ void RegenerateCommitments(CBlock& block, ChainstateManager& chainman)
58
77
 
59
78
  BlockAssembler::Options::Options()
60
79
  {
61
- blockMinFeeRate = CFeeRate(DEFAULT_BLOCK_MIN_TX_FEE);
62
80
  nBlockMaxWeight = DEFAULT_BLOCK_MAX_WEIGHT;
63
81
  }
64
82
 
@@ -67,7 +85,6 @@ BlockAssembler::BlockAssembler(CChainState& chainstate, const CTxMemPool& mempoo
67
85
  m_mempool(mempool),
68
86
  m_chainstate(chainstate)
69
87
  {
70
- blockMinFeeRate = options.blockMinFeeRate;
71
88
  // Limit weight to between 4K and MAX_BLOCK_WEIGHT-4K for sanity:
72
89
  nBlockMaxWeight = std::max<size_t>(4000, std::min<size_t>(MAX_BLOCK_WEIGHT - 4000, options.nBlockMaxWeight));
73
90
  }
@@ -78,12 +95,6 @@ static BlockAssembler::Options DefaultOptions()
78
95
  // If -blockmaxweight is not given, limit to DEFAULT_BLOCK_MAX_WEIGHT
79
96
  BlockAssembler::Options options;
80
97
  options.nBlockMaxWeight = gArgs.GetIntArg("-blockmaxweight", DEFAULT_BLOCK_MAX_WEIGHT);
81
- if (gArgs.IsArgSet("-blockmintxfee")) {
82
- std::optional<CAmount> parsed = ParseMoney(gArgs.GetArg("-blockmintxfee", ""));
83
- options.blockMinFeeRate = CFeeRate{parsed.value_or(DEFAULT_BLOCK_MIN_TX_FEE)};
84
- } else {
85
- options.blockMinFeeRate = CFeeRate{DEFAULT_BLOCK_MIN_TX_FEE};
86
- }
87
98
  return options;
88
99
  }
89
100
 
@@ -104,7 +115,8 @@ void BlockAssembler::resetBlock()
104
115
  nFees = 0;
105
116
  }
106
117
 
107
- std::unique_ptr<CBlockTemplate> BlockAssembler::CreateNewBlock(const CScript& scriptPubKeyIn)
118
+ // peercoin: if pwallet != NULL it will attempt to create coinstake
119
+ std::unique_ptr<CBlockTemplate> BlockAssembler::CreateNewBlock(const CScript& scriptPubKeyIn, CWallet* pwallet, bool* pfPoSCancel, NodeContext* m_node)
108
120
  {
109
121
  int64_t nTimeStart = GetTimeMicros();
110
122
 
@@ -116,25 +128,67 @@ std::unique_ptr<CBlockTemplate> BlockAssembler::CreateNewBlock(const CScript& sc
116
128
  return nullptr;
117
129
  }
118
130
  CBlock* const pblock = &pblocktemplate->block; // pointer for convenience
131
+ pblock->nTime = GetAdjustedTime();
132
+
133
+ LOCK2(cs_main, m_mempool.cs);
134
+
135
+ CBlockIndex* pindexPrev = m_node->chainman->ActiveChain().Tip();
136
+ assert(pindexPrev != nullptr);
137
+ nHeight = pindexPrev->nHeight + 1;
138
+
139
+ // Create coinbase transaction.
140
+ CMutableTransaction coinbaseTx;
141
+ coinbaseTx.vin.resize(1);
142
+ coinbaseTx.vin[0].prevout.SetNull();
143
+ coinbaseTx.vout.resize(1);
144
+ coinbaseTx.vout[0].scriptPubKey = scriptPubKeyIn;
145
+
146
+ if (pwallet == nullptr) {
147
+ pblock->nBits = GetNextTargetRequired(pindexPrev, false, chainparams.GetConsensus());
148
+ coinbaseTx.vout[0].nValue = GetProofOfWorkReward(pblock->nBits, pblock->nTime);
149
+ }
119
150
 
120
151
  // Add dummy coinbase tx as first transaction
121
152
  pblock->vtx.emplace_back();
122
153
  pblocktemplate->vTxFees.push_back(-1); // updated at end
123
154
  pblocktemplate->vTxSigOpsCost.push_back(-1); // updated at end
124
155
 
125
- LOCK2(cs_main, m_mempool.cs);
126
- CBlockIndex* pindexPrev = m_chainstate.m_chain.Tip();
127
- assert(pindexPrev != nullptr);
128
- nHeight = pindexPrev->nHeight + 1;
156
+ // peercoin: if coinstake available add coinstake tx
157
+ static int64_t nLastCoinStakeSearchTime = GetAdjustedTime(); // only initialized at startup
158
+
159
+ if (pwallet) // attemp to find a coinstake
160
+ {
161
+ *pfPoSCancel = true;
162
+ pblock->nBits = GetNextTargetRequired(pindexPrev, true, chainparams.GetConsensus());
163
+ CMutableTransaction txCoinStake;
164
+ int64_t nSearchTime = txCoinStake.nTime; // search to current time
165
+ if (nSearchTime > nLastCoinStakeSearchTime)
166
+ {
167
+ if (pwallet->CreateCoinStake(*m_node->chainman, pwallet, pblock->nBits, nSearchTime-nLastCoinStakeSearchTime, txCoinStake))
168
+ {
169
+ if (txCoinStake.nTime >= std::max(pindexPrev->GetMedianTimePast()+1, pindexPrev->GetBlockTime() - (IsProtocolV09(pindexPrev->GetBlockTime()) ? MAX_FUTURE_BLOCK_TIME : MAX_FUTURE_BLOCK_TIME_PREV9)))
170
+ { // make sure coinstake would meet timestamp protocol
171
+ // as it would be the same as the block timestamp
172
+ coinbaseTx.vout[0].SetEmpty();
173
+ coinbaseTx.nTime = txCoinStake.nTime;
174
+ pblock->vtx.push_back(MakeTransactionRef(CTransaction(txCoinStake)));
175
+ *pfPoSCancel = false;
176
+ }
177
+ }
178
+ nLastCoinStakeSearchInterval = nSearchTime - nLastCoinStakeSearchTime;
179
+ nLastCoinStakeSearchTime = nSearchTime;
180
+ }
181
+ if (*pfPoSCancel)
182
+ return nullptr; // peercoin: there is no point to continue if we failed to create coinstake
183
+ pblock->nFlags = CBlockIndex::BLOCK_PROOF_OF_STAKE;
184
+ }
129
185
 
130
- pblock->nVersion = g_versionbitscache.ComputeBlockVersion(pindexPrev, chainparams.GetConsensus());
131
186
  // -regtest only: allow overriding block.nVersion with
132
187
  // -blockversion=N to test forking scenarios
133
188
  if (chainparams.MineBlocksOnDemand()) {
134
189
  pblock->nVersion = gArgs.GetIntArg("-blockversion", pblock->nVersion);
135
190
  }
136
191
 
137
- pblock->nTime = GetAdjustedTime();
138
192
  m_lock_time_cutoff = pindexPrev->GetMedianTimePast();
139
193
 
140
194
  // Decide whether to include witness transactions
@@ -146,40 +200,38 @@ std::unique_ptr<CBlockTemplate> BlockAssembler::CreateNewBlock(const CScript& sc
146
200
  // not activated.
147
201
  // TODO: replace this with a call to main to assess validity of a mempool
148
202
  // transaction (which in most cases can be a no-op).
149
- fIncludeWitness = DeploymentActiveAfter(pindexPrev, chainparams.GetConsensus(), Consensus::DEPLOYMENT_SEGWIT);
203
+ fIncludeWitness = IsBTC16BIPsEnabled(pindexPrev->nTime);
150
204
 
151
205
  int nPackagesSelected = 0;
152
206
  int nDescendantsUpdated = 0;
153
- addPackageTxs(nPackagesSelected, nDescendantsUpdated);
207
+ addPackageTxs(nPackagesSelected, nDescendantsUpdated, pblock->nTime);
154
208
 
155
209
  int64_t nTime1 = GetTimeMicros();
156
210
 
157
211
  m_last_block_num_txs = nBlockTx;
158
212
  m_last_block_weight = nBlockWeight;
159
213
 
160
- // Create coinbase transaction.
161
- CMutableTransaction coinbaseTx;
162
- coinbaseTx.vin.resize(1);
163
- coinbaseTx.vin[0].prevout.SetNull();
164
- coinbaseTx.vout.resize(1);
165
- coinbaseTx.vout[0].scriptPubKey = scriptPubKeyIn;
166
- coinbaseTx.vout[0].nValue = nFees + GetBlockSubsidy(nHeight, chainparams.GetConsensus());
167
214
  coinbaseTx.vin[0].scriptSig = CScript() << nHeight << OP_0;
168
215
  pblock->vtx[0] = MakeTransactionRef(std::move(coinbaseTx));
169
- pblocktemplate->vchCoinbaseCommitment = GenerateCoinbaseCommitment(*pblock, pindexPrev, chainparams.GetConsensus());
216
+ if (fIncludeWitness)
217
+ pblocktemplate->vchCoinbaseCommitment = GenerateCoinbaseCommitment(*pblock, pindexPrev, chainparams.GetConsensus());
170
218
  pblocktemplate->vTxFees[0] = -nFees;
171
219
 
172
220
  LogPrintf("CreateNewBlock(): block weight: %u txs: %u fees: %ld sigops %d\n", GetBlockWeight(*pblock), nBlockTx, nFees, nBlockSigOpsCost);
173
221
 
174
222
  // Fill in header
175
223
  pblock->hashPrevBlock = pindexPrev->GetBlockHash();
176
- UpdateTime(pblock, chainparams.GetConsensus(), pindexPrev);
177
- pblock->nBits = GetNextWorkRequired(pindexPrev, pblock, chainparams.GetConsensus());
224
+ if (pblock->IsProofOfStake())
225
+ pblock->nTime = pblock->vtx[1]->nTime; //same as coinstake timestamp
226
+ pblock->nTime = std::max(pindexPrev->GetMedianTimePast()+1, pblock->GetMaxTransactionTime());
227
+ pblock->nTime = std::max(pblock->GetBlockTime(), pindexPrev->GetBlockTime() - (IsProtocolV09(pindexPrev->GetBlockTime()) ? MAX_FUTURE_BLOCK_TIME : MAX_FUTURE_BLOCK_TIME_PREV9));
228
+ if (pblock->IsProofOfWork())
229
+ UpdateTime(pblock);
178
230
  pblock->nNonce = 0;
179
231
  pblocktemplate->vTxSigOpsCost[0] = WITNESS_SCALE_FACTOR * GetLegacySigOpCount(*pblock->vtx[0]);
180
232
 
181
233
  BlockValidationState state;
182
- if (!TestBlockValidity(state, chainparams, m_chainstate, *pblock, pindexPrev, false, false)) {
234
+ if (pwallet && !TestBlockValidity(state, chainparams, m_chainstate, *pblock, pindexPrev, false, false)) {
183
235
  throw std::runtime_error(strprintf("%s: TestBlockValidity failed: %s", __func__, state.ToString()));
184
236
  }
185
237
  int64_t nTime2 = GetTimeMicros();
@@ -217,7 +269,7 @@ bool BlockAssembler::TestPackage(uint64_t packageSize, int64_t packageSigOpsCost
217
269
  // - transaction finality (locktime)
218
270
  // - premature witness (in case segwit transactions are added to mempool before
219
271
  // segwit activation)
220
- bool BlockAssembler::TestPackageTransactions(const CTxMemPool::setEntries& package) const
272
+ bool BlockAssembler::TestPackageTransactions(const CTxMemPool::setEntries& package, uint32_t nTime) const
221
273
  {
222
274
  for (CTxMemPool::txiter it : package) {
223
275
  if (!IsFinalTx(it->GetTx(), nHeight, m_lock_time_cutoff)) {
@@ -225,6 +277,10 @@ bool BlockAssembler::TestPackageTransactions(const CTxMemPool::setEntries& packa
225
277
  }
226
278
  if (!fIncludeWitness && it->GetTx().HasWitness()) {
227
279
  return false;
280
+
281
+ // peercoin: timestamp limit
282
+ if (it->GetTx().nTime > GetAdjustedTime() || (nTime && it->GetTx().nTime > nTime))
283
+ return false;
228
284
  }
229
285
  }
230
286
  return true;
@@ -243,8 +299,8 @@ void BlockAssembler::AddToBlock(CTxMemPool::txiter iter)
243
299
 
244
300
  bool fPrintPriority = gArgs.GetBoolArg("-printpriority", DEFAULT_PRINTPRIORITY);
245
301
  if (fPrintPriority) {
246
- LogPrintf("fee rate %s txid %s\n",
247
- CFeeRate(iter->GetModifiedFee(), iter->GetTxSize()).ToString(),
302
+ LogPrintf("fee %d satoshi txid %s\n",
303
+ iter->GetModifiedFee(),
248
304
  iter->GetTx().GetHash().ToString());
249
305
  }
250
306
  }
@@ -317,7 +373,7 @@ void BlockAssembler::SortForBlock(const CTxMemPool::setEntries& package, std::ve
317
373
  // Each time through the loop, we compare the best transaction in
318
374
  // mapModifiedTxs with the next transaction in the mempool to decide what
319
375
  // transaction package to work on next.
320
- void BlockAssembler::addPackageTxs(int& nPackagesSelected, int& nDescendantsUpdated)
376
+ void BlockAssembler::addPackageTxs(int& nPackagesSelected, int& nDescendantsUpdated, uint32_t nTime)
321
377
  {
322
378
  AssertLockHeld(m_mempool.cs);
323
379
 
@@ -379,19 +435,12 @@ void BlockAssembler::addPackageTxs(int& nPackagesSelected, int& nDescendantsUpda
379
435
  assert(!inBlock.count(iter));
380
436
 
381
437
  uint64_t packageSize = iter->GetSizeWithAncestors();
382
- CAmount packageFees = iter->GetModFeesWithAncestors();
383
438
  int64_t packageSigOpsCost = iter->GetSigOpCostWithAncestors();
384
439
  if (fUsingModified) {
385
440
  packageSize = modit->nSizeWithAncestors;
386
- packageFees = modit->nModFeesWithAncestors;
387
441
  packageSigOpsCost = modit->nSigOpCostWithAncestors;
388
442
  }
389
443
 
390
- if (packageFees < blockMinFeeRate.GetFee(packageSize)) {
391
- // Everything else we might consider has a lower fee rate
392
- return;
393
- }
394
-
395
444
  if (!TestPackage(packageSize, packageSigOpsCost)) {
396
445
  if (fUsingModified) {
397
446
  // Since we always look at the best entry in mapModifiedTx,
@@ -420,7 +469,7 @@ void BlockAssembler::addPackageTxs(int& nPackagesSelected, int& nDescendantsUpda
420
469
  ancestors.insert(iter);
421
470
 
422
471
  // Test if all tx's are Final
423
- if (!TestPackageTransactions(ancestors)) {
472
+ if (!TestPackageTransactions(ancestors,nTime)) {
424
473
  if (fUsingModified) {
425
474
  mapModifiedTx.get<ancestor_score>().erase(modit);
426
475
  failedTx.insert(iter);
@@ -465,4 +514,208 @@ void IncrementExtraNonce(CBlock* pblock, const CBlockIndex* pindexPrev, unsigned
465
514
  pblock->vtx[0] = MakeTransactionRef(std::move(txCoinbase));
466
515
  pblock->hashMerkleRoot = BlockMerkleRoot(*pblock);
467
516
  }
517
+
518
+
519
+ static bool ProcessBlockFound(const CBlock* pblock, const CChainParams& chainparams, NodeContext& m_node)
520
+ {
521
+ LogPrintf("%s\n", pblock->ToString());
522
+ LogPrintf("generated %s\n", FormatMoney(pblock->vtx[0]->vout[0].nValue));
523
+
524
+ // Found a solution
525
+ {
526
+ LOCK(cs_main);
527
+ if (pblock->hashPrevBlock != m_node.chainman->ActiveChain().Tip()->GetBlockHash())
528
+ return error("PeercoinMiner: generated block is stale");
529
+ }
530
+
531
+ // Process this block the same as if we had received it from another node
532
+ std::shared_ptr<const CBlock> shared_pblock = std::make_shared<const CBlock>(*pblock);
533
+ if (!m_node.chainman->ProcessNewBlock(Params(), shared_pblock, true, NULL))
534
+ return error("ProcessNewBlock, block not accepted");
535
+
536
+ return true;
537
+ }
538
+
539
+ void PoSMiner(std::shared_ptr<CWallet> pwallet, NodeContext& m_node)
540
+ {
541
+ CConnman* connman = m_node.connman.get();
542
+ LogPrintf("CPUMiner started for proof-of-stake\n");
543
+ util::ThreadRename("peercoin-stake-minter");
544
+
545
+ unsigned int nExtraNonce = 0;
546
+
547
+ OutputType output_type = pwallet->m_default_change_type ? *pwallet->m_default_change_type : pwallet->m_default_address_type;
548
+ ReserveDestination reservedest(pwallet.get(), output_type);
549
+ CTxDestination dest;
550
+ // Compute timeout for pos as sqrt(numUTXO)
551
+ unsigned int pos_timio;
552
+ {
553
+ LOCK2(pwallet->cs_wallet, cs_main);
554
+ bilingual_str dest_err;
555
+ if (!reservedest.GetReservedDestination(dest, true, dest_err))
556
+ throw std::runtime_error("Error: Keypool ran out, please call keypoolrefill first.");
557
+
558
+ std::vector<COutput> vCoins;
559
+ CCoinControl coincontrol;
560
+ AvailableCoins(*pwallet, vCoins, &coincontrol);
561
+ pos_timio = 500 + 30 * sqrt(vCoins.size());
562
+ LogPrintf("Set proof-of-stake timeout: %ums for %u UTXOs\n", pos_timio, vCoins.size());
563
+ }
564
+
565
+ std::string strMintMessage = _("Info: Minting suspended due to locked wallet.").translated;
566
+ std::string strMintSyncMessage = _("Info: Minting suspended while synchronizing wallet.").translated;
567
+ std::string strMintDisabledMessage = _("Info: Minting disabled by 'nominting' option.").translated;
568
+ std::string strMintBlockMessage = _("Info: Minting suspended due to block creation failure.").translated;
569
+ std::string strMintEmpty = "";
570
+ if (!gArgs.GetBoolArg("-minting", true) || !gArgs.GetBoolArg("-staking", true))
571
+ {
572
+ strMintWarning = strMintDisabledMessage;
573
+ LogPrintf("proof-of-stake minter disabled\n");
574
+ return;
575
+ }
576
+
577
+ try {
578
+ bool fNeedToClear = false;
579
+ while (true) {
580
+ while (pwallet->IsLocked()) {
581
+ if (strMintWarning != strMintMessage) {
582
+ strMintWarning = strMintMessage;
583
+ uiInterface.NotifyAlertChanged(uint256(), CT_UPDATED);
584
+ }
585
+ fNeedToClear = true;
586
+ if (!connman->interruptNet.sleep_for(std::chrono::seconds(3)))
587
+ return;
588
+ }
589
+
590
+ if (Params().MiningRequiresPeers()) {
591
+ // Busy-wait for the network to come online so we don't waste time mining
592
+ // on an obsolete chain. In regtest mode we expect to fly solo.
593
+ while(connman == nullptr || connman->GetNodeCount(ConnectionDirection::Both) == 0 || m_node.chainman->ActiveChainstate().IsInitialBlockDownload()) {
594
+ while(connman == nullptr) {UninterruptibleSleep(1s);}
595
+ if (!connman->interruptNet.sleep_for(std::chrono::seconds(10)))
596
+ return;
597
+ }
598
+ }
599
+
600
+ while (GuessVerificationProgress(Params().TxData(), m_node.chainman->ActiveChain().Tip()) < 0.996)
601
+ {
602
+ LogPrintf("Minter thread sleeps while sync at %f\n", GuessVerificationProgress(Params().TxData(), m_node.chainman->ActiveChain().Tip()));
603
+ if (strMintWarning != strMintSyncMessage) {
604
+ strMintWarning = strMintSyncMessage;
605
+ uiInterface.NotifyAlertChanged(uint256(), CT_UPDATED);
606
+ }
607
+ fNeedToClear = true;
608
+ if (!connman->interruptNet.sleep_for(std::chrono::seconds(10)))
609
+ return;
610
+ }
611
+ if (fNeedToClear) {
612
+ strMintWarning = strMintEmpty;
613
+ uiInterface.NotifyAlertChanged(uint256(), CT_UPDATED);
614
+ fNeedToClear = false;
615
+ }
616
+
617
+ //
618
+ // Create new block
619
+ //
620
+ CBlockIndex* pindexPrev = m_node.chainman->ActiveChain().Tip();
621
+ bool fPoSCancel = false;
622
+ CScript scriptPubKey = GetScriptForDestination(dest);
623
+ CBlock *pblock;
624
+ std::unique_ptr<CBlockTemplate> pblocktemplate;
625
+
626
+ {
627
+ LOCK2(pwallet->cs_wallet, cs_main);
628
+ try {
629
+ pblocktemplate = BlockAssembler(m_node.chainman->ActiveChainstate(), *m_node.mempool, Params()).CreateNewBlock(scriptPubKey, pwallet.get(), &fPoSCancel, &m_node);
630
+ }
631
+ catch (const std::runtime_error &e)
632
+ {
633
+ LogPrintf("PeercoinMiner runtime error: %s\n", e.what());
634
+ continue;
635
+ }
636
+ }
637
+
638
+ if (!pblocktemplate.get())
639
+ {
640
+ if (fPoSCancel == true)
641
+ {
642
+ if (!connman->interruptNet.sleep_for(std::chrono::milliseconds(pos_timio)))
643
+ return;
644
+ continue;
645
+ }
646
+ strMintWarning = strMintBlockMessage;
647
+ uiInterface.NotifyAlertChanged(uint256(), CT_UPDATED);
648
+ LogPrintf("Error in PeercoinMiner: Keypool ran out, please call keypoolrefill before restarting the mining thread\n");
649
+ if (!connman->interruptNet.sleep_for(std::chrono::seconds(10)))
650
+ return;
651
+
652
+ return;
653
+ }
654
+ pblock = &pblocktemplate->block;
655
+ IncrementExtraNonce(pblock, pindexPrev, nExtraNonce);
656
+
657
+ // peercoin: if proof-of-stake block found then process block
658
+ if (pblock->IsProofOfStake())
659
+ {
660
+ {
661
+ LOCK2(pwallet->cs_wallet, cs_main);
662
+ if (!SignBlock(*pblock, *pwallet))
663
+ {
664
+ LogPrintf("PoSMiner(): failed to sign PoS block");
665
+ continue;
666
+ }
667
+ }
668
+ LogPrintf("CPUMiner : proof-of-stake block found %s\n", pblock->GetHash().ToString());
669
+ try {
670
+ ProcessBlockFound(pblock, Params(), m_node);
671
+ }
672
+ catch (const std::runtime_error &e)
673
+ {
674
+ LogPrintf("PeercoinMiner runtime error: %s\n", e.what());
675
+ continue;
676
+ }
677
+ reservedest.KeepDestination();
678
+ // Rest for ~3 minutes after successful block to preserve close quick
679
+ if (!connman->interruptNet.sleep_for(std::chrono::seconds(60 + GetRand(4))))
680
+ return;
681
+ }
682
+ if (!connman->interruptNet.sleep_for(std::chrono::milliseconds(pos_timio)))
683
+ return;
684
+
685
+ continue;
686
+ }
687
+ }
688
+ catch (::boost::thread_interrupted)
689
+ {
690
+ LogPrintf("PeercoinMiner terminated\n");
691
+ return;
692
+ }
693
+ catch (const std::runtime_error &e)
694
+ {
695
+ LogPrintf("PeercoinMiner runtime error: %s\n", e.what());
696
+ return;
697
+ }
698
+ }
699
+
700
+ // peercoin: stake minter thread
701
+ void static ThreadStakeMinter(std::shared_ptr<CWallet> pwallet, NodeContext& m_node)
702
+ {
703
+ LogPrintf("ThreadStakeMinter started\n");
704
+ try
705
+ {
706
+ PoSMiner(pwallet, m_node);
707
+ }
708
+ catch (std::exception& e) {
709
+ PrintExceptionContinue(&e, "ThreadStakeMinter()");
710
+ } catch (...) {
711
+ PrintExceptionContinue(NULL, "ThreadStakeMinter()");
712
+ }
713
+ LogPrintf("ThreadStakeMinter exiting\n");
714
+ }
715
+
716
+ // peercoin: stake minter
717
+ void MintStake(std::shared_ptr<CWallet> pwallet, NodeContext& m_node)
718
+ {
719
+ m_minter_thread = std::thread([&] { util::TraceThread("minter", [&] { ThreadStakeMinter(pwallet, m_node); }); });
720
+ }
468
721
  } // namespace node
src/node/miner.h CHANGED
@@ -8,15 +8,18 @@
8
8
 
9
9
  #include <primitives/block.h>
10
10
  #include <txmempool.h>
11
-
11
+ #include <node/context.h>
12
12
  #include <memory>
13
13
  #include <optional>
14
14
  #include <stdint.h>
15
+ #include <wallet/wallet.h>
15
16
 
16
17
  #include <boost/multi_index/ordered_index.hpp>
17
18
  #include <boost/multi_index_container.hpp>
18
19
 
20
+ extern int64_t nLastCoinStakeSearchInterval;
19
21
  class ChainstateManager;
22
+
20
23
  class CBlockIndex;
21
24
  class CChainParams;
22
25
  class CScript;
@@ -134,7 +137,6 @@ private:
134
137
  // Configuration parameters for the block size
135
138
  bool fIncludeWitness;
136
139
  unsigned int nBlockMaxWeight;
137
- CFeeRate blockMinFeeRate;
138
140
 
139
141
  // Information on the current status of the block
140
142
  uint64_t nBlockWeight;
@@ -155,14 +157,14 @@ public:
155
157
  struct Options {
156
158
  Options();
157
159
  size_t nBlockMaxWeight;
158
- CFeeRate blockMinFeeRate;
159
160
  };
160
161
 
161
162
  explicit BlockAssembler(CChainState& chainstate, const CTxMemPool& mempool, const CChainParams& params);
162
163
  explicit BlockAssembler(CChainState& chainstate, const CTxMemPool& mempool, const CChainParams& params, const Options& options);
163
164
 
164
165
  /** Construct a new block template with coinbase to scriptPubKeyIn */
165
- std::unique_ptr<CBlockTemplate> CreateNewBlock(const CScript& scriptPubKeyIn);
166
+ std::unique_ptr<CBlockTemplate> CreateNewBlock(const CScript& scriptPubKeyIn, CWallet* pwallet=nullptr, bool* pfPoSCancel=nullptr, NodeContext* m_node=nullptr);
167
+ //std::unique_ptr<CBlockTemplate> CreateNewBlock(const CScript& scriptPubKeyIn);
166
168
 
167
169
  inline static std::optional<int64_t> m_last_block_num_txs{};
168
170
  inline static std::optional<int64_t> m_last_block_weight{};
@@ -178,7 +180,7 @@ private:
178
180
  /** Add transactions based on feerate including unconfirmed ancestors
179
181
  * Increments nPackagesSelected / nDescendantsUpdated with corresponding
180
182
  * statistics from the package selection (for logging statistics). */
181
- void addPackageTxs(int& nPackagesSelected, int& nDescendantsUpdated) EXCLUSIVE_LOCKS_REQUIRED(m_mempool.cs);
183
+ void addPackageTxs(int& nPackagesSelected, int& nDescendantsUpdated, uint32_t nTime) EXCLUSIVE_LOCKS_REQUIRED(m_mempool.cs);
182
184
 
183
185
  // helper functions for addPackageTxs()
184
186
  /** Remove confirmed (inBlock) entries from given set */
@@ -189,7 +191,7 @@ private:
189
191
  * locktime, premature-witness, serialized size (if necessary)
190
192
  * These checks should always succeed, and they're here
191
193
  * only as an extra check in case of suboptimal node configuration */
192
- bool TestPackageTransactions(const CTxMemPool::setEntries& package) const;
194
+ bool TestPackageTransactions(const CTxMemPool::setEntries& package, uint32_t nTime) const;
193
195
  /** Return true if given transaction from mapTx has already been evaluated,
194
196
  * or if the transaction's cached data in mapTx is incorrect. */
195
197
  bool SkipMapTxEntry(CTxMemPool::txiter it, indexed_modified_transaction_set& mapModifiedTx, CTxMemPool::setEntries& failedTx) EXCLUSIVE_LOCKS_REQUIRED(m_mempool.cs);
@@ -203,7 +205,13 @@ private:
203
205
 
204
206
  /** Modify the extranonce in a block */
205
207
  void IncrementExtraNonce(CBlock* pblock, const CBlockIndex* pindexPrev, unsigned int& nExtraNonce);
206
- int64_t UpdateTime(CBlockHeader* pblock, const Consensus::Params& consensusParams, const CBlockIndex* pindexPrev);
208
+ int64_t UpdateTime(CBlockHeader* pblock);
209
+
210
+ namespace boost {
211
+ class thread_group;
212
+ } // namespace boost
213
+
214
+ void MintStake(std::shared_ptr<CWallet> pwallet, NodeContext& m_node);
207
215
 
208
216
  /** Update an old GenerateCoinbaseCommitment from CreateNewBlock after the block txs have changed */
209
217
  void RegenerateCommitments(CBlock& block, ChainstateManager& chainman);
src/node/psbt.cpp CHANGED
@@ -5,9 +5,11 @@
5
5
  #include <coins.h>
6
6
  #include <consensus/amount.h>
7
7
  #include <consensus/tx_verify.h>
8
+ #include <kernel.h>
8
9
  #include <node/psbt.h>
9
10
  #include <policy/policy.h>
10
11
  #include <policy/settings.h>
12
+ #include <timedata.h>
11
13
  #include <tinyformat.h>
12
14
 
13
15
  #include <numeric>
@@ -131,7 +133,7 @@ PSBTAnalysis AnalyzePSBT(PartiallySignedTransaction psbtx)
131
133
  mtx.vin[i].scriptSig = input.final_script_sig;
132
134
  mtx.vin[i].scriptWitness = input.final_script_witness;
133
135
  newcoin.nHeight = 1;
134
- view.AddCoin(psbtx.tx->vin[i].prevout, std::move(newcoin), true);
136
+ view.AddCoin(psbtx.tx->vin[i].prevout, std::move(newcoin), true, true);
135
137
  }
136
138
  }
137
139
 
@@ -139,9 +141,6 @@ PSBTAnalysis AnalyzePSBT(PartiallySignedTransaction psbtx)
139
141
  CTransaction ctx = CTransaction(mtx);
140
142
  size_t size = GetVirtualTransactionSize(ctx, GetTransactionSigOpCost(ctx, view, STANDARD_SCRIPT_VERIFY_FLAGS));
141
143
  result.estimated_vsize = size;
142
- // Estimate fee rate
143
- CFeeRate feerate(fee, size);
144
- result.estimated_feerate = feerate;
145
144
  }
146
145
 
147
146
  }
src/node/psbt.h CHANGED
@@ -29,7 +29,6 @@ struct PSBTInputAnalysis {
29
29
  */
30
30
  struct PSBTAnalysis {
31
31
  std::optional<size_t> estimated_vsize; //!< Estimated weight of the transaction
32
- std::optional<CFeeRate> estimated_feerate; //!< Estimated feerate (fee / weight) of the transaction
33
32
  std::optional<CAmount> fee; //!< Amount of fee being paid by the transaction
34
33
  std::vector<PSBTInputAnalysis> inputs; //!< More information about the individual inputs of the transaction
35
34
  PSBTRole next; //!< Which of the BIP 174 roles needs to handle the transaction next
@@ -38,7 +37,6 @@ struct PSBTAnalysis {
38
37
  void SetInvalid(std::string err_msg)
39
38
  {
40
39
  estimated_vsize = std::nullopt;
41
- estimated_feerate = std::nullopt;
42
40
  fee = std::nullopt;
43
41
  inputs.clear();
44
42
  next = PSBTRole::CREATOR;
src/node/transaction.cpp CHANGED
@@ -30,7 +30,7 @@ static TransactionError HandleATMPError(const TxValidationState& state, std::str
30
30
  }
31
31
  }
32
32
 
33
- TransactionError BroadcastTransaction(NodeContext& node, const CTransactionRef tx, std::string& err_string, const CAmount& max_tx_fee, bool relay, bool wait_callback)
33
+ TransactionError BroadcastTransaction(NodeContext& node, const CTransactionRef tx, std::string& err_string, bool relay, bool wait_callback)
34
34
  {
35
35
  // BroadcastTransaction can be called by either sendrawtransaction RPC or the wallet.
36
36
  // chainman, mempool and peerman are initialized before the RPC server and wallet are started
@@ -68,16 +68,6 @@ TransactionError BroadcastTransaction(NodeContext& node, const CTransactionRef t
68
68
  wtxid = mempool_tx->GetWitnessHash();
69
69
  } else {
70
70
  // Transaction is not already in the mempool.
71
- if (max_tx_fee > 0) {
72
- // First, call ATMP with test_accept and check the fee. If ATMP
73
- // fails here, return error immediately.
74
- const MempoolAcceptResult result = node.chainman->ProcessTransaction(tx, /*test_accept=*/ true);
75
- if (result.m_result_type != MempoolAcceptResult::ResultType::VALID) {
76
- return HandleATMPError(result.m_state, err_string);
77
- } else if (result.m_base_fees.value() > max_tx_fee) {
78
- return TransactionError::MAX_FEE_EXCEEDED;
79
- }
80
- }
81
71
  // Try to submit the transaction to the mempool.
82
72
  const MempoolAcceptResult result = node.chainman->ProcessTransaction(tx, /*test_accept=*/ false);
83
73
  if (result.m_result_type != MempoolAcceptResult::ResultType::VALID) {
src/node/transaction.h CHANGED
@@ -6,7 +6,6 @@
6
6
  #define BITCOIN_NODE_TRANSACTION_H
7
7
 
8
8
  #include <attributes.h>
9
- #include <policy/feerate.h>
10
9
  #include <primitives/transaction.h>
11
10
  #include <util/error.h>
12
11
 
@@ -19,13 +18,6 @@ struct Params;
19
18
  namespace node {
20
19
  struct NodeContext;
21
20
 
22
- /** Maximum fee rate for sendrawtransaction and testmempoolaccept RPC calls.
23
- * Also used by the GUI when broadcasting a completed PSBT.
24
- * By default, a transaction with a fee rate higher than this will be rejected
25
- * by these RPCs and the GUI. This can be overridden with the maxfeerate argument.
26
- */
27
- static const CFeeRate DEFAULT_MAX_RAW_TX_FEE_RATE{COIN / 10};
28
-
29
21
  /**
30
22
  * Submit a transaction to the mempool and (optionally) relay it to all P2P peers.
31
23
  *
@@ -38,12 +30,11 @@ static const CFeeRate DEFAULT_MAX_RAW_TX_FEE_RATE{COIN / 10};
38
30
  * @param[in] node reference to node context
39
31
  * @param[in] tx the transaction to broadcast
40
32
  * @param[out] err_string reference to std::string to fill with error string if available
41
- * @param[in] max_tx_fee reject txs with fees higher than this (if 0, accept any fee)
42
33
  * @param[in] relay flag if both mempool insertion and p2p relay are requested
43
34
  * @param[in] wait_callback wait until callbacks have been processed to avoid stale result due to a sequentially RPC.
44
35
  * return error
45
36
  */
46
- [[nodiscard]] TransactionError BroadcastTransaction(NodeContext& node, CTransactionRef tx, std::string& err_string, const CAmount& max_tx_fee, bool relay, bool wait_callback);
37
+ [[nodiscard]] TransactionError BroadcastTransaction(NodeContext& node, CTransactionRef tx, std::string& err_string, bool relay, bool wait_callback);
47
38
 
48
39
  /**
49
40
  * Return transaction with a given hash.
src/node/ui_interface.cpp CHANGED
@@ -50,7 +50,7 @@ void CClientUIInterface::InitMessage(const std::string& message) { return g_ui_s
50
50
  void CClientUIInterface::InitWallet() { return g_ui_signals.InitWallet(); }
51
51
  void CClientUIInterface::NotifyNumConnectionsChanged(int newNumConnections) { return g_ui_signals.NotifyNumConnectionsChanged(newNumConnections); }
52
52
  void CClientUIInterface::NotifyNetworkActiveChanged(bool networkActive) { return g_ui_signals.NotifyNetworkActiveChanged(networkActive); }
53
- void CClientUIInterface::NotifyAlertChanged() { return g_ui_signals.NotifyAlertChanged(); }
53
+ void CClientUIInterface::NotifyAlertChanged(const uint256 &hash, ChangeType status) { return g_ui_signals.NotifyAlertChanged(hash, status); }
54
54
  void CClientUIInterface::ShowProgress(const std::string& title, int nProgress, bool resume_possible) { return g_ui_signals.ShowProgress(title, nProgress, resume_possible); }
55
55
  void CClientUIInterface::NotifyBlockTip(SynchronizationState s, const CBlockIndex* i) { return g_ui_signals.NotifyBlockTip(s, i); }
56
56
  void CClientUIInterface::NotifyHeaderTip(SynchronizationState s, const CBlockIndex* i) { return g_ui_signals.NotifyHeaderTip(s, i); }
src/node/ui_interface.h CHANGED
@@ -9,8 +9,10 @@
9
9
  #include <functional>
10
10
  #include <memory>
11
11
  #include <string>
12
+ #include <util/ui_change_type.h>
12
13
 
13
14
  class CBlockIndex;
15
+ class uint256;
14
16
  enum class SynchronizationState;
15
17
  struct bilingual_str;
16
18
 
@@ -93,7 +95,7 @@ public:
93
95
  /**
94
96
  * Status bar alerts changed.
95
97
  */
96
- ADD_SIGNALS_DECL_WRAPPER(NotifyAlertChanged, void, );
98
+ ADD_SIGNALS_DECL_WRAPPER(NotifyAlertChanged, void, const uint256 &hash, ChangeType status);
97
99
 
98
100
  /**
99
101
  * Show progress e.g. for verifychain.
src/policy/feerate.cpp DELETED
@@ -1,45 +0,0 @@
1
- // Copyright (c) 2009-2010 Satoshi Nakamoto
2
- // Copyright (c) 2009-2021 The Bitcoin Core developers
3
- // Distributed under the MIT software license, see the accompanying
4
- // file COPYING or http://www.opensource.org/licenses/mit-license.php.
5
-
6
- #include <policy/feerate.h>
7
-
8
- #include <tinyformat.h>
9
-
10
- #include <cmath>
11
-
12
- CFeeRate::CFeeRate(const CAmount& nFeePaid, uint32_t num_bytes)
13
- {
14
- const int64_t nSize{num_bytes};
15
-
16
- if (nSize > 0) {
17
- nSatoshisPerK = nFeePaid * 1000 / nSize;
18
- } else {
19
- nSatoshisPerK = 0;
20
- }
21
- }
22
-
23
- CAmount CFeeRate::GetFee(uint32_t num_bytes) const
24
- {
25
- const int64_t nSize{num_bytes};
26
-
27
- // Be explicit that we're converting from a double to int64_t (CAmount) here.
28
- // We've previously had issues with the silent double->int64_t conversion.
29
- CAmount nFee{static_cast<CAmount>(std::ceil(nSatoshisPerK * nSize / 1000.0))};
30
-
31
- if (nFee == 0 && nSize != 0) {
32
- if (nSatoshisPerK > 0) nFee = CAmount(1);
33
- if (nSatoshisPerK < 0) nFee = CAmount(-1);
34
- }
35
-
36
- return nFee;
37
- }
38
-
39
- std::string CFeeRate::ToString(const FeeEstimateMode& fee_estimate_mode) const
40
- {
41
- switch (fee_estimate_mode) {
42
- case FeeEstimateMode::SAT_VB: return strprintf("%d.%03d %s/vB", nSatoshisPerK / 1000, nSatoshisPerK % 1000, CURRENCY_ATOM);
43
- default: return strprintf("%d.%08d %s/kvB", nSatoshisPerK / COIN, nSatoshisPerK % COIN, CURRENCY_UNIT);
44
- }
45
- }
src/policy/feerate.h DELETED
@@ -1,75 +0,0 @@
1
- // Copyright (c) 2009-2010 Satoshi Nakamoto
2
- // Copyright (c) 2009-2021 The Bitcoin Core developers
3
- // Distributed under the MIT software license, see the accompanying
4
- // file COPYING or http://www.opensource.org/licenses/mit-license.php.
5
-
6
- #ifndef BITCOIN_POLICY_FEERATE_H
7
- #define BITCOIN_POLICY_FEERATE_H
8
-
9
- #include <consensus/amount.h>
10
- #include <serialize.h>
11
-
12
- #include <string>
13
-
14
- const std::string CURRENCY_UNIT = "BTC"; // One formatted unit
15
- const std::string CURRENCY_ATOM = "sat"; // One indivisible minimum value unit
16
-
17
- /* Used to determine type of fee estimation requested */
18
- enum class FeeEstimateMode {
19
- UNSET, //!< Use default settings based on other criteria
20
- ECONOMICAL, //!< Force estimateSmartFee to use non-conservative estimates
21
- CONSERVATIVE, //!< Force estimateSmartFee to use conservative estimates
22
- BTC_KVB, //!< Use BTC/kvB fee rate unit
23
- SAT_VB, //!< Use sat/vB fee rate unit
24
- };
25
-
26
- /**
27
- * Fee rate in satoshis per kilovirtualbyte: CAmount / kvB
28
- */
29
- class CFeeRate
30
- {
31
- private:
32
- /** Fee rate in sat/kvB (satoshis per 1000 virtualbytes) */
33
- CAmount nSatoshisPerK;
34
-
35
- public:
36
- /** Fee rate of 0 satoshis per kvB */
37
- CFeeRate() : nSatoshisPerK(0) { }
38
- template<typename I>
39
- explicit CFeeRate(const I _nSatoshisPerK): nSatoshisPerK(_nSatoshisPerK) {
40
- // We've previously had bugs creep in from silent double->int conversion...
41
- static_assert(std::is_integral<I>::value, "CFeeRate should be used without floats");
42
- }
43
-
44
- /**
45
- * Construct a fee rate from a fee in satoshis and a vsize in vB.
46
- *
47
- * param@[in] nFeePaid The fee paid by a transaction, in satoshis
48
- * param@[in] num_bytes The vsize of a transaction, in vbytes
49
- */
50
- CFeeRate(const CAmount& nFeePaid, uint32_t num_bytes);
51
-
52
- /**
53
- * Return the fee in satoshis for the given vsize in vbytes.
54
- * If the calculated fee would have fractional satoshis, then the
55
- * returned fee will always be rounded up to the nearest satoshi.
56
- */
57
- CAmount GetFee(uint32_t num_bytes) const;
58
-
59
- /**
60
- * Return the fee in satoshis for a vsize of 1000 vbytes
61
- */
62
- CAmount GetFeePerK() const { return GetFee(1000); }
63
- friend bool operator<(const CFeeRate& a, const CFeeRate& b) { return a.nSatoshisPerK < b.nSatoshisPerK; }
64
- friend bool operator>(const CFeeRate& a, const CFeeRate& b) { return a.nSatoshisPerK > b.nSatoshisPerK; }
65
- friend bool operator==(const CFeeRate& a, const CFeeRate& b) { return a.nSatoshisPerK == b.nSatoshisPerK; }
66
- friend bool operator<=(const CFeeRate& a, const CFeeRate& b) { return a.nSatoshisPerK <= b.nSatoshisPerK; }
67
- friend bool operator>=(const CFeeRate& a, const CFeeRate& b) { return a.nSatoshisPerK >= b.nSatoshisPerK; }
68
- friend bool operator!=(const CFeeRate& a, const CFeeRate& b) { return a.nSatoshisPerK != b.nSatoshisPerK; }
69
- CFeeRate& operator+=(const CFeeRate& a) { nSatoshisPerK += a.nSatoshisPerK; return *this; }
70
- std::string ToString(const FeeEstimateMode& fee_estimate_mode = FeeEstimateMode::BTC_KVB) const;
71
-
72
- SERIALIZE_METHODS(CFeeRate, obj) { READWRITE(obj.nSatoshisPerK); }
73
- };
74
-
75
- #endif // BITCOIN_POLICY_FEERATE_H
src/policy/fees.cpp DELETED
@@ -1,1017 +0,0 @@
1
- // Copyright (c) 2009-2010 Satoshi Nakamoto
2
- // Copyright (c) 2009-2021 The Bitcoin Core developers
3
- // Distributed under the MIT software license, see the accompanying
4
- // file COPYING or http://www.opensource.org/licenses/mit-license.php.
5
-
6
- #include <policy/fees.h>
7
-
8
- #include <clientversion.h>
9
- #include <fs.h>
10
- #include <logging.h>
11
- #include <streams.h>
12
- #include <txmempool.h>
13
- #include <util/serfloat.h>
14
- #include <util/system.h>
15
-
16
- static const char* FEE_ESTIMATES_FILENAME = "fee_estimates.dat";
17
-
18
- static constexpr double INF_FEERATE = 1e99;
19
-
20
- std::string StringForFeeEstimateHorizon(FeeEstimateHorizon horizon)
21
- {
22
- switch (horizon) {
23
- case FeeEstimateHorizon::SHORT_HALFLIFE: return "short";
24
- case FeeEstimateHorizon::MED_HALFLIFE: return "medium";
25
- case FeeEstimateHorizon::LONG_HALFLIFE: return "long";
26
- } // no default case, so the compiler can warn about missing cases
27
- assert(false);
28
- }
29
-
30
- namespace {
31
-
32
- struct EncodedDoubleFormatter
33
- {
34
- template<typename Stream> void Ser(Stream &s, double v)
35
- {
36
- s << EncodeDouble(v);
37
- }
38
-
39
- template<typename Stream> void Unser(Stream& s, double& v)
40
- {
41
- uint64_t encoded;
42
- s >> encoded;
43
- v = DecodeDouble(encoded);
44
- }
45
- };
46
-
47
- } // namespace
48
-
49
- /**
50
- * We will instantiate an instance of this class to track transactions that were
51
- * included in a block. We will lump transactions into a bucket according to their
52
- * approximate feerate and then track how long it took for those txs to be included in a block
53
- *
54
- * The tracking of unconfirmed (mempool) transactions is completely independent of the
55
- * historical tracking of transactions that have been confirmed in a block.
56
- */
57
- class TxConfirmStats
58
- {
59
- private:
60
- //Define the buckets we will group transactions into
61
- const std::vector<double>& buckets; // The upper-bound of the range for the bucket (inclusive)
62
- const std::map<double, unsigned int>& bucketMap; // Map of bucket upper-bound to index into all vectors by bucket
63
-
64
- // For each bucket X:
65
- // Count the total # of txs in each bucket
66
- // Track the historical moving average of this total over blocks
67
- std::vector<double> txCtAvg;
68
-
69
- // Count the total # of txs confirmed within Y blocks in each bucket
70
- // Track the historical moving average of these totals over blocks
71
- std::vector<std::vector<double>> confAvg; // confAvg[Y][X]
72
-
73
- // Track moving avg of txs which have been evicted from the mempool
74
- // after failing to be confirmed within Y blocks
75
- std::vector<std::vector<double>> failAvg; // failAvg[Y][X]
76
-
77
- // Sum the total feerate of all tx's in each bucket
78
- // Track the historical moving average of this total over blocks
79
- std::vector<double> m_feerate_avg;
80
-
81
- // Combine the conf counts with tx counts to calculate the confirmation % for each Y,X
82
- // Combine the total value with the tx counts to calculate the avg feerate per bucket
83
-
84
- double decay;
85
-
86
- // Resolution (# of blocks) with which confirmations are tracked
87
- unsigned int scale;
88
-
89
- // Mempool counts of outstanding transactions
90
- // For each bucket X, track the number of transactions in the mempool
91
- // that are unconfirmed for each possible confirmation value Y
92
- std::vector<std::vector<int> > unconfTxs; //unconfTxs[Y][X]
93
- // transactions still unconfirmed after GetMaxConfirms for each bucket
94
- std::vector<int> oldUnconfTxs;
95
-
96
- void resizeInMemoryCounters(size_t newbuckets);
97
-
98
- public:
99
- /**
100
- * Create new TxConfirmStats. This is called by BlockPolicyEstimator's
101
- * constructor with default values.
102
- * @param defaultBuckets contains the upper limits for the bucket boundaries
103
- * @param maxPeriods max number of periods to track
104
- * @param decay how much to decay the historical moving average per block
105
- */
106
- TxConfirmStats(const std::vector<double>& defaultBuckets, const std::map<double, unsigned int>& defaultBucketMap,
107
- unsigned int maxPeriods, double decay, unsigned int scale);
108
-
109
- /** Roll the circular buffer for unconfirmed txs*/
110
- void ClearCurrent(unsigned int nBlockHeight);
111
-
112
- /**
113
- * Record a new transaction data point in the current block stats
114
- * @param blocksToConfirm the number of blocks it took this transaction to confirm
115
- * @param val the feerate of the transaction
116
- * @warning blocksToConfirm is 1-based and has to be >= 1
117
- */
118
- void Record(int blocksToConfirm, double val);
119
-
120
- /** Record a new transaction entering the mempool*/
121
- unsigned int NewTx(unsigned int nBlockHeight, double val);
122
-
123
- /** Remove a transaction from mempool tracking stats*/
124
- void removeTx(unsigned int entryHeight, unsigned int nBestSeenHeight,
125
- unsigned int bucketIndex, bool inBlock);
126
-
127
- /** Update our estimates by decaying our historical moving average and updating
128
- with the data gathered from the current block */
129
- void UpdateMovingAverages();
130
-
131
- /**
132
- * Calculate a feerate estimate. Find the lowest value bucket (or range of buckets
133
- * to make sure we have enough data points) whose transactions still have sufficient likelihood
134
- * of being confirmed within the target number of confirmations
135
- * @param confTarget target number of confirmations
136
- * @param sufficientTxVal required average number of transactions per block in a bucket range
137
- * @param minSuccess the success probability we require
138
- * @param nBlockHeight the current block height
139
- */
140
- double EstimateMedianVal(int confTarget, double sufficientTxVal,
141
- double minSuccess, unsigned int nBlockHeight,
142
- EstimationResult *result = nullptr) const;
143
-
144
- /** Return the max number of confirms we're tracking */
145
- unsigned int GetMaxConfirms() const { return scale * confAvg.size(); }
146
-
147
- /** Write state of estimation data to a file*/
148
- void Write(CAutoFile& fileout) const;
149
-
150
- /**
151
- * Read saved state of estimation data from a file and replace all internal data structures and
152
- * variables with this state.
153
- */
154
- void Read(CAutoFile& filein, int nFileVersion, size_t numBuckets);
155
- };
156
-
157
-
158
- TxConfirmStats::TxConfirmStats(const std::vector<double>& defaultBuckets,
159
- const std::map<double, unsigned int>& defaultBucketMap,
160
- unsigned int maxPeriods, double _decay, unsigned int _scale)
161
- : buckets(defaultBuckets), bucketMap(defaultBucketMap), decay(_decay), scale(_scale)
162
- {
163
- assert(_scale != 0 && "_scale must be non-zero");
164
- confAvg.resize(maxPeriods);
165
- failAvg.resize(maxPeriods);
166
- for (unsigned int i = 0; i < maxPeriods; i++) {
167
- confAvg[i].resize(buckets.size());
168
- failAvg[i].resize(buckets.size());
169
- }
170
-
171
- txCtAvg.resize(buckets.size());
172
- m_feerate_avg.resize(buckets.size());
173
-
174
- resizeInMemoryCounters(buckets.size());
175
- }
176
-
177
- void TxConfirmStats::resizeInMemoryCounters(size_t newbuckets) {
178
- // newbuckets must be passed in because the buckets referred to during Read have not been updated yet.
179
- unconfTxs.resize(GetMaxConfirms());
180
- for (unsigned int i = 0; i < unconfTxs.size(); i++) {
181
- unconfTxs[i].resize(newbuckets);
182
- }
183
- oldUnconfTxs.resize(newbuckets);
184
- }
185
-
186
- // Roll the unconfirmed txs circular buffer
187
- void TxConfirmStats::ClearCurrent(unsigned int nBlockHeight)
188
- {
189
- for (unsigned int j = 0; j < buckets.size(); j++) {
190
- oldUnconfTxs[j] += unconfTxs[nBlockHeight % unconfTxs.size()][j];
191
- unconfTxs[nBlockHeight%unconfTxs.size()][j] = 0;
192
- }
193
- }
194
-
195
-
196
- void TxConfirmStats::Record(int blocksToConfirm, double feerate)
197
- {
198
- // blocksToConfirm is 1-based
199
- if (blocksToConfirm < 1)
200
- return;
201
- int periodsToConfirm = (blocksToConfirm + scale - 1) / scale;
202
- unsigned int bucketindex = bucketMap.lower_bound(feerate)->second;
203
- for (size_t i = periodsToConfirm; i <= confAvg.size(); i++) {
204
- confAvg[i - 1][bucketindex]++;
205
- }
206
- txCtAvg[bucketindex]++;
207
- m_feerate_avg[bucketindex] += feerate;
208
- }
209
-
210
- void TxConfirmStats::UpdateMovingAverages()
211
- {
212
- assert(confAvg.size() == failAvg.size());
213
- for (unsigned int j = 0; j < buckets.size(); j++) {
214
- for (unsigned int i = 0; i < confAvg.size(); i++) {
215
- confAvg[i][j] *= decay;
216
- failAvg[i][j] *= decay;
217
- }
218
- m_feerate_avg[j] *= decay;
219
- txCtAvg[j] *= decay;
220
- }
221
- }
222
-
223
- // returns -1 on error conditions
224
- double TxConfirmStats::EstimateMedianVal(int confTarget, double sufficientTxVal,
225
- double successBreakPoint, unsigned int nBlockHeight,
226
- EstimationResult *result) const
227
- {
228
- // Counters for a bucket (or range of buckets)
229
- double nConf = 0; // Number of tx's confirmed within the confTarget
230
- double totalNum = 0; // Total number of tx's that were ever confirmed
231
- int extraNum = 0; // Number of tx's still in mempool for confTarget or longer
232
- double failNum = 0; // Number of tx's that were never confirmed but removed from the mempool after confTarget
233
- const int periodTarget = (confTarget + scale - 1) / scale;
234
- const int maxbucketindex = buckets.size() - 1;
235
-
236
- // We'll combine buckets until we have enough samples.
237
- // The near and far variables will define the range we've combined
238
- // The best variables are the last range we saw which still had a high
239
- // enough confirmation rate to count as success.
240
- // The cur variables are the current range we're counting.
241
- unsigned int curNearBucket = maxbucketindex;
242
- unsigned int bestNearBucket = maxbucketindex;
243
- unsigned int curFarBucket = maxbucketindex;
244
- unsigned int bestFarBucket = maxbucketindex;
245
-
246
- bool foundAnswer = false;
247
- unsigned int bins = unconfTxs.size();
248
- bool newBucketRange = true;
249
- bool passing = true;
250
- EstimatorBucket passBucket;
251
- EstimatorBucket failBucket;
252
-
253
- // Start counting from highest feerate transactions
254
- for (int bucket = maxbucketindex; bucket >= 0; --bucket) {
255
- if (newBucketRange) {
256
- curNearBucket = bucket;
257
- newBucketRange = false;
258
- }
259
- curFarBucket = bucket;
260
- nConf += confAvg[periodTarget - 1][bucket];
261
- totalNum += txCtAvg[bucket];
262
- failNum += failAvg[periodTarget - 1][bucket];
263
- for (unsigned int confct = confTarget; confct < GetMaxConfirms(); confct++)
264
- extraNum += unconfTxs[(nBlockHeight - confct) % bins][bucket];
265
- extraNum += oldUnconfTxs[bucket];
266
- // If we have enough transaction data points in this range of buckets,
267
- // we can test for success
268
- // (Only count the confirmed data points, so that each confirmation count
269
- // will be looking at the same amount of data and same bucket breaks)
270
- if (totalNum >= sufficientTxVal / (1 - decay)) {
271
- double curPct = nConf / (totalNum + failNum + extraNum);
272
-
273
- // Check to see if we are no longer getting confirmed at the success rate
274
- if (curPct < successBreakPoint) {
275
- if (passing == true) {
276
- // First time we hit a failure record the failed bucket
277
- unsigned int failMinBucket = std::min(curNearBucket, curFarBucket);
278
- unsigned int failMaxBucket = std::max(curNearBucket, curFarBucket);
279
- failBucket.start = failMinBucket ? buckets[failMinBucket - 1] : 0;
280
- failBucket.end = buckets[failMaxBucket];
281
- failBucket.withinTarget = nConf;
282
- failBucket.totalConfirmed = totalNum;
283
- failBucket.inMempool = extraNum;
284
- failBucket.leftMempool = failNum;
285
- passing = false;
286
- }
287
- continue;
288
- }
289
- // Otherwise update the cumulative stats, and the bucket variables
290
- // and reset the counters
291
- else {
292
- failBucket = EstimatorBucket(); // Reset any failed bucket, currently passing
293
- foundAnswer = true;
294
- passing = true;
295
- passBucket.withinTarget = nConf;
296
- nConf = 0;
297
- passBucket.totalConfirmed = totalNum;
298
- totalNum = 0;
299
- passBucket.inMempool = extraNum;
300
- passBucket.leftMempool = failNum;
301
- failNum = 0;
302
- extraNum = 0;
303
- bestNearBucket = curNearBucket;
304
- bestFarBucket = curFarBucket;
305
- newBucketRange = true;
306
- }
307
- }
308
- }
309
-
310
- double median = -1;
311
- double txSum = 0;
312
-
313
- // Calculate the "average" feerate of the best bucket range that met success conditions
314
- // Find the bucket with the median transaction and then report the average feerate from that bucket
315
- // This is a compromise between finding the median which we can't since we don't save all tx's
316
- // and reporting the average which is less accurate
317
- unsigned int minBucket = std::min(bestNearBucket, bestFarBucket);
318
- unsigned int maxBucket = std::max(bestNearBucket, bestFarBucket);
319
- for (unsigned int j = minBucket; j <= maxBucket; j++) {
320
- txSum += txCtAvg[j];
321
- }
322
- if (foundAnswer && txSum != 0) {
323
- txSum = txSum / 2;
324
- for (unsigned int j = minBucket; j <= maxBucket; j++) {
325
- if (txCtAvg[j] < txSum)
326
- txSum -= txCtAvg[j];
327
- else { // we're in the right bucket
328
- median = m_feerate_avg[j] / txCtAvg[j];
329
- break;
330
- }
331
- }
332
-
333
- passBucket.start = minBucket ? buckets[minBucket-1] : 0;
334
- passBucket.end = buckets[maxBucket];
335
- }
336
-
337
- // If we were passing until we reached last few buckets with insufficient data, then report those as failed
338
- if (passing && !newBucketRange) {
339
- unsigned int failMinBucket = std::min(curNearBucket, curFarBucket);
340
- unsigned int failMaxBucket = std::max(curNearBucket, curFarBucket);
341
- failBucket.start = failMinBucket ? buckets[failMinBucket - 1] : 0;
342
- failBucket.end = buckets[failMaxBucket];
343
- failBucket.withinTarget = nConf;
344
- failBucket.totalConfirmed = totalNum;
345
- failBucket.inMempool = extraNum;
346
- failBucket.leftMempool = failNum;
347
- }
348
-
349
- float passed_within_target_perc = 0.0;
350
- float failed_within_target_perc = 0.0;
351
- if ((passBucket.totalConfirmed + passBucket.inMempool + passBucket.leftMempool)) {
352
- passed_within_target_perc = 100 * passBucket.withinTarget / (passBucket.totalConfirmed + passBucket.inMempool + passBucket.leftMempool);
353
- }
354
- if ((failBucket.totalConfirmed + failBucket.inMempool + failBucket.leftMempool)) {
355
- failed_within_target_perc = 100 * failBucket.withinTarget / (failBucket.totalConfirmed + failBucket.inMempool + failBucket.leftMempool);
356
- }
357
-
358
- LogPrint(BCLog::ESTIMATEFEE, "FeeEst: %d > %.0f%% decay %.5f: feerate: %g from (%g - %g) %.2f%% %.1f/(%.1f %d mem %.1f out) Fail: (%g - %g) %.2f%% %.1f/(%.1f %d mem %.1f out)\n",
359
- confTarget, 100.0 * successBreakPoint, decay,
360
- median, passBucket.start, passBucket.end,
361
- passed_within_target_perc,
362
- passBucket.withinTarget, passBucket.totalConfirmed, passBucket.inMempool, passBucket.leftMempool,
363
- failBucket.start, failBucket.end,
364
- failed_within_target_perc,
365
- failBucket.withinTarget, failBucket.totalConfirmed, failBucket.inMempool, failBucket.leftMempool);
366
-
367
-
368
- if (result) {
369
- result->pass = passBucket;
370
- result->fail = failBucket;
371
- result->decay = decay;
372
- result->scale = scale;
373
- }
374
- return median;
375
- }
376
-
377
- void TxConfirmStats::Write(CAutoFile& fileout) const
378
- {
379
- fileout << Using<EncodedDoubleFormatter>(decay);
380
- fileout << scale;
381
- fileout << Using<VectorFormatter<EncodedDoubleFormatter>>(m_feerate_avg);
382
- fileout << Using<VectorFormatter<EncodedDoubleFormatter>>(txCtAvg);
383
- fileout << Using<VectorFormatter<VectorFormatter<EncodedDoubleFormatter>>>(confAvg);
384
- fileout << Using<VectorFormatter<VectorFormatter<EncodedDoubleFormatter>>>(failAvg);
385
- }
386
-
387
- void TxConfirmStats::Read(CAutoFile& filein, int nFileVersion, size_t numBuckets)
388
- {
389
- // Read data file and do some very basic sanity checking
390
- // buckets and bucketMap are not updated yet, so don't access them
391
- // If there is a read failure, we'll just discard this entire object anyway
392
- size_t maxConfirms, maxPeriods;
393
-
394
- // The current version will store the decay with each individual TxConfirmStats and also keep a scale factor
395
- filein >> Using<EncodedDoubleFormatter>(decay);
396
- if (decay <= 0 || decay >= 1) {
397
- throw std::runtime_error("Corrupt estimates file. Decay must be between 0 and 1 (non-inclusive)");
398
- }
399
- filein >> scale;
400
- if (scale == 0) {
401
- throw std::runtime_error("Corrupt estimates file. Scale must be non-zero");
402
- }
403
-
404
- filein >> Using<VectorFormatter<EncodedDoubleFormatter>>(m_feerate_avg);
405
- if (m_feerate_avg.size() != numBuckets) {
406
- throw std::runtime_error("Corrupt estimates file. Mismatch in feerate average bucket count");
407
- }
408
- filein >> Using<VectorFormatter<EncodedDoubleFormatter>>(txCtAvg);
409
- if (txCtAvg.size() != numBuckets) {
410
- throw std::runtime_error("Corrupt estimates file. Mismatch in tx count bucket count");
411
- }
412
- filein >> Using<VectorFormatter<VectorFormatter<EncodedDoubleFormatter>>>(confAvg);
413
- maxPeriods = confAvg.size();
414
- maxConfirms = scale * maxPeriods;
415
-
416
- if (maxConfirms <= 0 || maxConfirms > 6 * 24 * 7) { // one week
417
- throw std::runtime_error("Corrupt estimates file. Must maintain estimates for between 1 and 1008 (one week) confirms");
418
- }
419
- for (unsigned int i = 0; i < maxPeriods; i++) {
420
- if (confAvg[i].size() != numBuckets) {
421
- throw std::runtime_error("Corrupt estimates file. Mismatch in feerate conf average bucket count");
422
- }
423
- }
424
-
425
- filein >> Using<VectorFormatter<VectorFormatter<EncodedDoubleFormatter>>>(failAvg);
426
- if (maxPeriods != failAvg.size()) {
427
- throw std::runtime_error("Corrupt estimates file. Mismatch in confirms tracked for failures");
428
- }
429
- for (unsigned int i = 0; i < maxPeriods; i++) {
430
- if (failAvg[i].size() != numBuckets) {
431
- throw std::runtime_error("Corrupt estimates file. Mismatch in one of failure average bucket counts");
432
- }
433
- }
434
-
435
- // Resize the current block variables which aren't stored in the data file
436
- // to match the number of confirms and buckets
437
- resizeInMemoryCounters(numBuckets);
438
-
439
- LogPrint(BCLog::ESTIMATEFEE, "Reading estimates: %u buckets counting confirms up to %u blocks\n",
440
- numBuckets, maxConfirms);
441
- }
442
-
443
- unsigned int TxConfirmStats::NewTx(unsigned int nBlockHeight, double val)
444
- {
445
- unsigned int bucketindex = bucketMap.lower_bound(val)->second;
446
- unsigned int blockIndex = nBlockHeight % unconfTxs.size();
447
- unconfTxs[blockIndex][bucketindex]++;
448
- return bucketindex;
449
- }
450
-
451
- void TxConfirmStats::removeTx(unsigned int entryHeight, unsigned int nBestSeenHeight, unsigned int bucketindex, bool inBlock)
452
- {
453
- //nBestSeenHeight is not updated yet for the new block
454
- int blocksAgo = nBestSeenHeight - entryHeight;
455
- if (nBestSeenHeight == 0) // the BlockPolicyEstimator hasn't seen any blocks yet
456
- blocksAgo = 0;
457
- if (blocksAgo < 0) {
458
- LogPrint(BCLog::ESTIMATEFEE, "Blockpolicy error, blocks ago is negative for mempool tx\n");
459
- return; //This can't happen because we call this with our best seen height, no entries can have higher
460
- }
461
-
462
- if (blocksAgo >= (int)unconfTxs.size()) {
463
- if (oldUnconfTxs[bucketindex] > 0) {
464
- oldUnconfTxs[bucketindex]--;
465
- } else {
466
- LogPrint(BCLog::ESTIMATEFEE, "Blockpolicy error, mempool tx removed from >25 blocks,bucketIndex=%u already\n",
467
- bucketindex);
468
- }
469
- }
470
- else {
471
- unsigned int blockIndex = entryHeight % unconfTxs.size();
472
- if (unconfTxs[blockIndex][bucketindex] > 0) {
473
- unconfTxs[blockIndex][bucketindex]--;
474
- } else {
475
- LogPrint(BCLog::ESTIMATEFEE, "Blockpolicy error, mempool tx removed from blockIndex=%u,bucketIndex=%u already\n",
476
- blockIndex, bucketindex);
477
- }
478
- }
479
- if (!inBlock && (unsigned int)blocksAgo >= scale) { // Only counts as a failure if not confirmed for entire period
480
- assert(scale != 0);
481
- unsigned int periodsAgo = blocksAgo / scale;
482
- for (size_t i = 0; i < periodsAgo && i < failAvg.size(); i++) {
483
- failAvg[i][bucketindex]++;
484
- }
485
- }
486
- }
487
-
488
- // This function is called from CTxMemPool::removeUnchecked to ensure
489
- // txs removed from the mempool for any reason are no longer
490
- // tracked. Txs that were part of a block have already been removed in
491
- // processBlockTx to ensure they are never double tracked, but it is
492
- // of no harm to try to remove them again.
493
- bool CBlockPolicyEstimator::removeTx(uint256 hash, bool inBlock)
494
- {
495
- LOCK(m_cs_fee_estimator);
496
- return _removeTx(hash, inBlock);
497
- }
498
-
499
- bool CBlockPolicyEstimator::_removeTx(const uint256& hash, bool inBlock)
500
- {
501
- AssertLockHeld(m_cs_fee_estimator);
502
- std::map<uint256, TxStatsInfo>::iterator pos = mapMemPoolTxs.find(hash);
503
- if (pos != mapMemPoolTxs.end()) {
504
- feeStats->removeTx(pos->second.blockHeight, nBestSeenHeight, pos->second.bucketIndex, inBlock);
505
- shortStats->removeTx(pos->second.blockHeight, nBestSeenHeight, pos->second.bucketIndex, inBlock);
506
- longStats->removeTx(pos->second.blockHeight, nBestSeenHeight, pos->second.bucketIndex, inBlock);
507
- mapMemPoolTxs.erase(hash);
508
- return true;
509
- } else {
510
- return false;
511
- }
512
- }
513
-
514
- CBlockPolicyEstimator::CBlockPolicyEstimator()
515
- : nBestSeenHeight(0), firstRecordedHeight(0), historicalFirst(0), historicalBest(0), trackedTxs(0), untrackedTxs(0)
516
- {
517
- static_assert(MIN_BUCKET_FEERATE > 0, "Min feerate must be nonzero");
518
- size_t bucketIndex = 0;
519
-
520
- for (double bucketBoundary = MIN_BUCKET_FEERATE; bucketBoundary <= MAX_BUCKET_FEERATE; bucketBoundary *= FEE_SPACING, bucketIndex++) {
521
- buckets.push_back(bucketBoundary);
522
- bucketMap[bucketBoundary] = bucketIndex;
523
- }
524
- buckets.push_back(INF_FEERATE);
525
- bucketMap[INF_FEERATE] = bucketIndex;
526
- assert(bucketMap.size() == buckets.size());
527
-
528
- feeStats = std::unique_ptr<TxConfirmStats>(new TxConfirmStats(buckets, bucketMap, MED_BLOCK_PERIODS, MED_DECAY, MED_SCALE));
529
- shortStats = std::unique_ptr<TxConfirmStats>(new TxConfirmStats(buckets, bucketMap, SHORT_BLOCK_PERIODS, SHORT_DECAY, SHORT_SCALE));
530
- longStats = std::unique_ptr<TxConfirmStats>(new TxConfirmStats(buckets, bucketMap, LONG_BLOCK_PERIODS, LONG_DECAY, LONG_SCALE));
531
-
532
- // If the fee estimation file is present, read recorded estimations
533
- fs::path est_filepath = gArgs.GetDataDirNet() / FEE_ESTIMATES_FILENAME;
534
- CAutoFile est_file(fsbridge::fopen(est_filepath, "rb"), SER_DISK, CLIENT_VERSION);
535
- if (est_file.IsNull() || !Read(est_file)) {
536
- LogPrintf("Failed to read fee estimates from %s. Continue anyway.\n", fs::PathToString(est_filepath));
537
- }
538
- }
539
-
540
- CBlockPolicyEstimator::~CBlockPolicyEstimator()
541
- {
542
- }
543
-
544
- void CBlockPolicyEstimator::processTransaction(const CTxMemPoolEntry& entry, bool validFeeEstimate)
545
- {
546
- LOCK(m_cs_fee_estimator);
547
- unsigned int txHeight = entry.GetHeight();
548
- uint256 hash = entry.GetTx().GetHash();
549
- if (mapMemPoolTxs.count(hash)) {
550
- LogPrint(BCLog::ESTIMATEFEE, "Blockpolicy error mempool tx %s already being tracked\n",
551
- hash.ToString());
552
- return;
553
- }
554
-
555
- if (txHeight != nBestSeenHeight) {
556
- // Ignore side chains and re-orgs; assuming they are random they don't
557
- // affect the estimate. We'll potentially double count transactions in 1-block reorgs.
558
- // Ignore txs if BlockPolicyEstimator is not in sync with ActiveChain().Tip().
559
- // It will be synced next time a block is processed.
560
- return;
561
- }
562
-
563
- // Only want to be updating estimates when our blockchain is synced,
564
- // otherwise we'll miscalculate how many blocks its taking to get included.
565
- if (!validFeeEstimate) {
566
- untrackedTxs++;
567
- return;
568
- }
569
- trackedTxs++;
570
-
571
- // Feerates are stored and reported as BTC-per-kb:
572
- CFeeRate feeRate(entry.GetFee(), entry.GetTxSize());
573
-
574
- mapMemPoolTxs[hash].blockHeight = txHeight;
575
- unsigned int bucketIndex = feeStats->NewTx(txHeight, (double)feeRate.GetFeePerK());
576
- mapMemPoolTxs[hash].bucketIndex = bucketIndex;
577
- unsigned int bucketIndex2 = shortStats->NewTx(txHeight, (double)feeRate.GetFeePerK());
578
- assert(bucketIndex == bucketIndex2);
579
- unsigned int bucketIndex3 = longStats->NewTx(txHeight, (double)feeRate.GetFeePerK());
580
- assert(bucketIndex == bucketIndex3);
581
- }
582
-
583
- bool CBlockPolicyEstimator::processBlockTx(unsigned int nBlockHeight, const CTxMemPoolEntry* entry)
584
- {
585
- AssertLockHeld(m_cs_fee_estimator);
586
- if (!_removeTx(entry->GetTx().GetHash(), true)) {
587
- // This transaction wasn't being tracked for fee estimation
588
- return false;
589
- }
590
-
591
- // How many blocks did it take for miners to include this transaction?
592
- // blocksToConfirm is 1-based, so a transaction included in the earliest
593
- // possible block has confirmation count of 1
594
- int blocksToConfirm = nBlockHeight - entry->GetHeight();
595
- if (blocksToConfirm <= 0) {
596
- // This can't happen because we don't process transactions from a block with a height
597
- // lower than our greatest seen height
598
- LogPrint(BCLog::ESTIMATEFEE, "Blockpolicy error Transaction had negative blocksToConfirm\n");
599
- return false;
600
- }
601
-
602
- // Feerates are stored and reported as BTC-per-kb:
603
- CFeeRate feeRate(entry->GetFee(), entry->GetTxSize());
604
-
605
- feeStats->Record(blocksToConfirm, (double)feeRate.GetFeePerK());
606
- shortStats->Record(blocksToConfirm, (double)feeRate.GetFeePerK());
607
- longStats->Record(blocksToConfirm, (double)feeRate.GetFeePerK());
608
- return true;
609
- }
610
-
611
- void CBlockPolicyEstimator::processBlock(unsigned int nBlockHeight,
612
- std::vector<const CTxMemPoolEntry*>& entries)
613
- {
614
- LOCK(m_cs_fee_estimator);
615
- if (nBlockHeight <= nBestSeenHeight) {
616
- // Ignore side chains and re-orgs; assuming they are random
617
- // they don't affect the estimate.
618
- // And if an attacker can re-org the chain at will, then
619
- // you've got much bigger problems than "attacker can influence
620
- // transaction fees."
621
- return;
622
- }
623
-
624
- // Must update nBestSeenHeight in sync with ClearCurrent so that
625
- // calls to removeTx (via processBlockTx) correctly calculate age
626
- // of unconfirmed txs to remove from tracking.
627
- nBestSeenHeight = nBlockHeight;
628
-
629
- // Update unconfirmed circular buffer
630
- feeStats->ClearCurrent(nBlockHeight);
631
- shortStats->ClearCurrent(nBlockHeight);
632
- longStats->ClearCurrent(nBlockHeight);
633
-
634
- // Decay all exponential averages
635
- feeStats->UpdateMovingAverages();
636
- shortStats->UpdateMovingAverages();
637
- longStats->UpdateMovingAverages();
638
-
639
- unsigned int countedTxs = 0;
640
- // Update averages with data points from current block
641
- for (const auto& entry : entries) {
642
- if (processBlockTx(nBlockHeight, entry))
643
- countedTxs++;
644
- }
645
-
646
- if (firstRecordedHeight == 0 && countedTxs > 0) {
647
- firstRecordedHeight = nBestSeenHeight;
648
- LogPrint(BCLog::ESTIMATEFEE, "Blockpolicy first recorded height %u\n", firstRecordedHeight);
649
- }
650
-
651
-
652
- LogPrint(BCLog::ESTIMATEFEE, "Blockpolicy estimates updated by %u of %u block txs, since last block %u of %u tracked, mempool map size %u, max target %u from %s\n",
653
- countedTxs, entries.size(), trackedTxs, trackedTxs + untrackedTxs, mapMemPoolTxs.size(),
654
- MaxUsableEstimate(), HistoricalBlockSpan() > BlockSpan() ? "historical" : "current");
655
-
656
- trackedTxs = 0;
657
- untrackedTxs = 0;
658
- }
659
-
660
- CFeeRate CBlockPolicyEstimator::estimateFee(int confTarget) const
661
- {
662
- // It's not possible to get reasonable estimates for confTarget of 1
663
- if (confTarget <= 1)
664
- return CFeeRate(0);
665
-
666
- return estimateRawFee(confTarget, DOUBLE_SUCCESS_PCT, FeeEstimateHorizon::MED_HALFLIFE);
667
- }
668
-
669
- CFeeRate CBlockPolicyEstimator::estimateRawFee(int confTarget, double successThreshold, FeeEstimateHorizon horizon, EstimationResult* result) const
670
- {
671
- TxConfirmStats* stats = nullptr;
672
- double sufficientTxs = SUFFICIENT_FEETXS;
673
- switch (horizon) {
674
- case FeeEstimateHorizon::SHORT_HALFLIFE: {
675
- stats = shortStats.get();
676
- sufficientTxs = SUFFICIENT_TXS_SHORT;
677
- break;
678
- }
679
- case FeeEstimateHorizon::MED_HALFLIFE: {
680
- stats = feeStats.get();
681
- break;
682
- }
683
- case FeeEstimateHorizon::LONG_HALFLIFE: {
684
- stats = longStats.get();
685
- break;
686
- }
687
- } // no default case, so the compiler can warn about missing cases
688
- assert(stats);
689
-
690
- LOCK(m_cs_fee_estimator);
691
- // Return failure if trying to analyze a target we're not tracking
692
- if (confTarget <= 0 || (unsigned int)confTarget > stats->GetMaxConfirms())
693
- return CFeeRate(0);
694
- if (successThreshold > 1)
695
- return CFeeRate(0);
696
-
697
- double median = stats->EstimateMedianVal(confTarget, sufficientTxs, successThreshold, nBestSeenHeight, result);
698
-
699
- if (median < 0)
700
- return CFeeRate(0);
701
-
702
- return CFeeRate(llround(median));
703
- }
704
-
705
- unsigned int CBlockPolicyEstimator::HighestTargetTracked(FeeEstimateHorizon horizon) const
706
- {
707
- LOCK(m_cs_fee_estimator);
708
- switch (horizon) {
709
- case FeeEstimateHorizon::SHORT_HALFLIFE: {
710
- return shortStats->GetMaxConfirms();
711
- }
712
- case FeeEstimateHorizon::MED_HALFLIFE: {
713
- return feeStats->GetMaxConfirms();
714
- }
715
- case FeeEstimateHorizon::LONG_HALFLIFE: {
716
- return longStats->GetMaxConfirms();
717
- }
718
- } // no default case, so the compiler can warn about missing cases
719
- assert(false);
720
- }
721
-
722
- unsigned int CBlockPolicyEstimator::BlockSpan() const
723
- {
724
- if (firstRecordedHeight == 0) return 0;
725
- assert(nBestSeenHeight >= firstRecordedHeight);
726
-
727
- return nBestSeenHeight - firstRecordedHeight;
728
- }
729
-
730
- unsigned int CBlockPolicyEstimator::HistoricalBlockSpan() const
731
- {
732
- if (historicalFirst == 0) return 0;
733
- assert(historicalBest >= historicalFirst);
734
-
735
- if (nBestSeenHeight - historicalBest > OLDEST_ESTIMATE_HISTORY) return 0;
736
-
737
- return historicalBest - historicalFirst;
738
- }
739
-
740
- unsigned int CBlockPolicyEstimator::MaxUsableEstimate() const
741
- {
742
- // Block spans are divided by 2 to make sure there are enough potential failing data points for the estimate
743
- return std::min(longStats->GetMaxConfirms(), std::max(BlockSpan(), HistoricalBlockSpan()) / 2);
744
- }
745
-
746
- /** Return a fee estimate at the required successThreshold from the shortest
747
- * time horizon which tracks confirmations up to the desired target. If
748
- * checkShorterHorizon is requested, also allow short time horizon estimates
749
- * for a lower target to reduce the given answer */
750
- double CBlockPolicyEstimator::estimateCombinedFee(unsigned int confTarget, double successThreshold, bool checkShorterHorizon, EstimationResult *result) const
751
- {
752
- double estimate = -1;
753
- if (confTarget >= 1 && confTarget <= longStats->GetMaxConfirms()) {
754
- // Find estimate from shortest time horizon possible
755
- if (confTarget <= shortStats->GetMaxConfirms()) { // short horizon
756
- estimate = shortStats->EstimateMedianVal(confTarget, SUFFICIENT_TXS_SHORT, successThreshold, nBestSeenHeight, result);
757
- }
758
- else if (confTarget <= feeStats->GetMaxConfirms()) { // medium horizon
759
- estimate = feeStats->EstimateMedianVal(confTarget, SUFFICIENT_FEETXS, successThreshold, nBestSeenHeight, result);
760
- }
761
- else { // long horizon
762
- estimate = longStats->EstimateMedianVal(confTarget, SUFFICIENT_FEETXS, successThreshold, nBestSeenHeight, result);
763
- }
764
- if (checkShorterHorizon) {
765
- EstimationResult tempResult;
766
- // If a lower confTarget from a more recent horizon returns a lower answer use it.
767
- if (confTarget > feeStats->GetMaxConfirms()) {
768
- double medMax = feeStats->EstimateMedianVal(feeStats->GetMaxConfirms(), SUFFICIENT_FEETXS, successThreshold, nBestSeenHeight, &tempResult);
769
- if (medMax > 0 && (estimate == -1 || medMax < estimate)) {
770
- estimate = medMax;
771
- if (result) *result = tempResult;
772
- }
773
- }
774
- if (confTarget > shortStats->GetMaxConfirms()) {
775
- double shortMax = shortStats->EstimateMedianVal(shortStats->GetMaxConfirms(), SUFFICIENT_TXS_SHORT, successThreshold, nBestSeenHeight, &tempResult);
776
- if (shortMax > 0 && (estimate == -1 || shortMax < estimate)) {
777
- estimate = shortMax;
778
- if (result) *result = tempResult;
779
- }
780
- }
781
- }
782
- }
783
- return estimate;
784
- }
785
-
786
- /** Ensure that for a conservative estimate, the DOUBLE_SUCCESS_PCT is also met
787
- * at 2 * target for any longer time horizons.
788
- */
789
- double CBlockPolicyEstimator::estimateConservativeFee(unsigned int doubleTarget, EstimationResult *result) const
790
- {
791
- double estimate = -1;
792
- EstimationResult tempResult;
793
- if (doubleTarget <= shortStats->GetMaxConfirms()) {
794
- estimate = feeStats->EstimateMedianVal(doubleTarget, SUFFICIENT_FEETXS, DOUBLE_SUCCESS_PCT, nBestSeenHeight, result);
795
- }
796
- if (doubleTarget <= feeStats->GetMaxConfirms()) {
797
- double longEstimate = longStats->EstimateMedianVal(doubleTarget, SUFFICIENT_FEETXS, DOUBLE_SUCCESS_PCT, nBestSeenHeight, &tempResult);
798
- if (longEstimate > estimate) {
799
- estimate = longEstimate;
800
- if (result) *result = tempResult;
801
- }
802
- }
803
- return estimate;
804
- }
805
-
806
- /** estimateSmartFee returns the max of the feerates calculated with a 60%
807
- * threshold required at target / 2, an 85% threshold required at target and a
808
- * 95% threshold required at 2 * target. Each calculation is performed at the
809
- * shortest time horizon which tracks the required target. Conservative
810
- * estimates, however, required the 95% threshold at 2 * target be met for any
811
- * longer time horizons also.
812
- */
813
- CFeeRate CBlockPolicyEstimator::estimateSmartFee(int confTarget, FeeCalculation *feeCalc, bool conservative) const
814
- {
815
- LOCK(m_cs_fee_estimator);
816
-
817
- if (feeCalc) {
818
- feeCalc->desiredTarget = confTarget;
819
- feeCalc->returnedTarget = confTarget;
820
- }
821
-
822
- double median = -1;
823
- EstimationResult tempResult;
824
-
825
- // Return failure if trying to analyze a target we're not tracking
826
- if (confTarget <= 0 || (unsigned int)confTarget > longStats->GetMaxConfirms()) {
827
- return CFeeRate(0); // error condition
828
- }
829
-
830
- // It's not possible to get reasonable estimates for confTarget of 1
831
- if (confTarget == 1) confTarget = 2;
832
-
833
- unsigned int maxUsableEstimate = MaxUsableEstimate();
834
- if ((unsigned int)confTarget > maxUsableEstimate) {
835
- confTarget = maxUsableEstimate;
836
- }
837
- if (feeCalc) feeCalc->returnedTarget = confTarget;
838
-
839
- if (confTarget <= 1) return CFeeRate(0); // error condition
840
-
841
- assert(confTarget > 0); //estimateCombinedFee and estimateConservativeFee take unsigned ints
842
- /** true is passed to estimateCombined fee for target/2 and target so
843
- * that we check the max confirms for shorter time horizons as well.
844
- * This is necessary to preserve monotonically increasing estimates.
845
- * For non-conservative estimates we do the same thing for 2*target, but
846
- * for conservative estimates we want to skip these shorter horizons
847
- * checks for 2*target because we are taking the max over all time
848
- * horizons so we already have monotonically increasing estimates and
849
- * the purpose of conservative estimates is not to let short term
850
- * fluctuations lower our estimates by too much.
851
- */
852
- double halfEst = estimateCombinedFee(confTarget/2, HALF_SUCCESS_PCT, true, &tempResult);
853
- if (feeCalc) {
854
- feeCalc->est = tempResult;
855
- feeCalc->reason = FeeReason::HALF_ESTIMATE;
856
- }
857
- median = halfEst;
858
- double actualEst = estimateCombinedFee(confTarget, SUCCESS_PCT, true, &tempResult);
859
- if (actualEst > median) {
860
- median = actualEst;
861
- if (feeCalc) {
862
- feeCalc->est = tempResult;
863
- feeCalc->reason = FeeReason::FULL_ESTIMATE;
864
- }
865
- }
866
- double doubleEst = estimateCombinedFee(2 * confTarget, DOUBLE_SUCCESS_PCT, !conservative, &tempResult);
867
- if (doubleEst > median) {
868
- median = doubleEst;
869
- if (feeCalc) {
870
- feeCalc->est = tempResult;
871
- feeCalc->reason = FeeReason::DOUBLE_ESTIMATE;
872
- }
873
- }
874
-
875
- if (conservative || median == -1) {
876
- double consEst = estimateConservativeFee(2 * confTarget, &tempResult);
877
- if (consEst > median) {
878
- median = consEst;
879
- if (feeCalc) {
880
- feeCalc->est = tempResult;
881
- feeCalc->reason = FeeReason::CONSERVATIVE;
882
- }
883
- }
884
- }
885
-
886
- if (median < 0) return CFeeRate(0); // error condition
887
-
888
- return CFeeRate(llround(median));
889
- }
890
-
891
- void CBlockPolicyEstimator::Flush() {
892
- FlushUnconfirmed();
893
-
894
- fs::path est_filepath = gArgs.GetDataDirNet() / FEE_ESTIMATES_FILENAME;
895
- CAutoFile est_file(fsbridge::fopen(est_filepath, "wb"), SER_DISK, CLIENT_VERSION);
896
- if (est_file.IsNull() || !Write(est_file)) {
897
- LogPrintf("Failed to write fee estimates to %s. Continue anyway.\n", fs::PathToString(est_filepath));
898
- }
899
- }
900
-
901
- bool CBlockPolicyEstimator::Write(CAutoFile& fileout) const
902
- {
903
- try {
904
- LOCK(m_cs_fee_estimator);
905
- fileout << 149900; // version required to read: 0.14.99 or later
906
- fileout << CLIENT_VERSION; // version that wrote the file
907
- fileout << nBestSeenHeight;
908
- if (BlockSpan() > HistoricalBlockSpan()/2) {
909
- fileout << firstRecordedHeight << nBestSeenHeight;
910
- }
911
- else {
912
- fileout << historicalFirst << historicalBest;
913
- }
914
- fileout << Using<VectorFormatter<EncodedDoubleFormatter>>(buckets);
915
- feeStats->Write(fileout);
916
- shortStats->Write(fileout);
917
- longStats->Write(fileout);
918
- }
919
- catch (const std::exception&) {
920
- LogPrintf("CBlockPolicyEstimator::Write(): unable to write policy estimator data (non-fatal)\n");
921
- return false;
922
- }
923
- return true;
924
- }
925
-
926
- bool CBlockPolicyEstimator::Read(CAutoFile& filein)
927
- {
928
- try {
929
- LOCK(m_cs_fee_estimator);
930
- int nVersionRequired, nVersionThatWrote;
931
- filein >> nVersionRequired >> nVersionThatWrote;
932
- if (nVersionRequired > CLIENT_VERSION) {
933
- throw std::runtime_error(strprintf("up-version (%d) fee estimate file", nVersionRequired));
934
- }
935
-
936
- // Read fee estimates file into temporary variables so existing data
937
- // structures aren't corrupted if there is an exception.
938
- unsigned int nFileBestSeenHeight;
939
- filein >> nFileBestSeenHeight;
940
-
941
- if (nVersionRequired < 149900) {
942
- LogPrintf("%s: incompatible old fee estimation data (non-fatal). Version: %d\n", __func__, nVersionRequired);
943
- } else { // New format introduced in 149900
944
- unsigned int nFileHistoricalFirst, nFileHistoricalBest;
945
- filein >> nFileHistoricalFirst >> nFileHistoricalBest;
946
- if (nFileHistoricalFirst > nFileHistoricalBest || nFileHistoricalBest > nFileBestSeenHeight) {
947
- throw std::runtime_error("Corrupt estimates file. Historical block range for estimates is invalid");
948
- }
949
- std::vector<double> fileBuckets;
950
- filein >> Using<VectorFormatter<EncodedDoubleFormatter>>(fileBuckets);
951
- size_t numBuckets = fileBuckets.size();
952
- if (numBuckets <= 1 || numBuckets > 1000) {
953
- throw std::runtime_error("Corrupt estimates file. Must have between 2 and 1000 feerate buckets");
954
- }
955
-
956
- std::unique_ptr<TxConfirmStats> fileFeeStats(new TxConfirmStats(buckets, bucketMap, MED_BLOCK_PERIODS, MED_DECAY, MED_SCALE));
957
- std::unique_ptr<TxConfirmStats> fileShortStats(new TxConfirmStats(buckets, bucketMap, SHORT_BLOCK_PERIODS, SHORT_DECAY, SHORT_SCALE));
958
- std::unique_ptr<TxConfirmStats> fileLongStats(new TxConfirmStats(buckets, bucketMap, LONG_BLOCK_PERIODS, LONG_DECAY, LONG_SCALE));
959
- fileFeeStats->Read(filein, nVersionThatWrote, numBuckets);
960
- fileShortStats->Read(filein, nVersionThatWrote, numBuckets);
961
- fileLongStats->Read(filein, nVersionThatWrote, numBuckets);
962
-
963
- // Fee estimates file parsed correctly
964
- // Copy buckets from file and refresh our bucketmap
965
- buckets = fileBuckets;
966
- bucketMap.clear();
967
- for (unsigned int i = 0; i < buckets.size(); i++) {
968
- bucketMap[buckets[i]] = i;
969
- }
970
-
971
- // Destroy old TxConfirmStats and point to new ones that already reference buckets and bucketMap
972
- feeStats = std::move(fileFeeStats);
973
- shortStats = std::move(fileShortStats);
974
- longStats = std::move(fileLongStats);
975
-
976
- nBestSeenHeight = nFileBestSeenHeight;
977
- historicalFirst = nFileHistoricalFirst;
978
- historicalBest = nFileHistoricalBest;
979
- }
980
- }
981
- catch (const std::exception& e) {
982
- LogPrintf("CBlockPolicyEstimator::Read(): unable to read policy estimator data (non-fatal): %s\n",e.what());
983
- return false;
984
- }
985
- return true;
986
- }
987
-
988
- void CBlockPolicyEstimator::FlushUnconfirmed() {
989
- int64_t startclear = GetTimeMicros();
990
- LOCK(m_cs_fee_estimator);
991
- size_t num_entries = mapMemPoolTxs.size();
992
- // Remove every entry in mapMemPoolTxs
993
- while (!mapMemPoolTxs.empty()) {
994
- auto mi = mapMemPoolTxs.begin();
995
- _removeTx(mi->first, false); // this calls erase() on mapMemPoolTxs
996
- }
997
- int64_t endclear = GetTimeMicros();
998
- LogPrint(BCLog::ESTIMATEFEE, "Recorded %u unconfirmed txs from mempool in %gs\n", num_entries, (endclear - startclear)*0.000001);
999
- }
1000
-
1001
- FeeFilterRounder::FeeFilterRounder(const CFeeRate& minIncrementalFee)
1002
- {
1003
- CAmount minFeeLimit = std::max(CAmount(1), minIncrementalFee.GetFeePerK() / 2);
1004
- feeset.insert(0);
1005
- for (double bucketBoundary = minFeeLimit; bucketBoundary <= MAX_FILTER_FEERATE; bucketBoundary *= FEE_FILTER_SPACING) {
1006
- feeset.insert(bucketBoundary);
1007
- }
1008
- }
1009
-
1010
- CAmount FeeFilterRounder::round(CAmount currentMinFee)
1011
- {
1012
- std::set<double>::iterator it = feeset.lower_bound(currentMinFee);
1013
- if ((it != feeset.begin() && insecure_rand.rand32() % 3 != 0) || it == feeset.end()) {
1014
- it--;
1015
- }
1016
- return static_cast<CAmount>(*it);
1017
- }
src/policy/fees.h DELETED
@@ -1,310 +0,0 @@
1
- // Copyright (c) 2009-2010 Satoshi Nakamoto
2
- // Copyright (c) 2009-2021 The Bitcoin Core developers
3
- // Distributed under the MIT software license, see the accompanying
4
- // file COPYING or http://www.opensource.org/licenses/mit-license.php.
5
- #ifndef BITCOIN_POLICY_FEES_H
6
- #define BITCOIN_POLICY_FEES_H
7
-
8
- #include <consensus/amount.h>
9
- #include <policy/feerate.h>
10
- #include <uint256.h>
11
- #include <random.h>
12
- #include <sync.h>
13
-
14
- #include <array>
15
- #include <map>
16
- #include <memory>
17
- #include <string>
18
- #include <vector>
19
-
20
- class CAutoFile;
21
- class CFeeRate;
22
- class CTxMemPoolEntry;
23
- class CTxMemPool;
24
- class TxConfirmStats;
25
-
26
- /* Identifier for each of the 3 different TxConfirmStats which will track
27
- * history over different time horizons. */
28
- enum class FeeEstimateHorizon {
29
- SHORT_HALFLIFE,
30
- MED_HALFLIFE,
31
- LONG_HALFLIFE,
32
- };
33
-
34
- static constexpr auto ALL_FEE_ESTIMATE_HORIZONS = std::array{
35
- FeeEstimateHorizon::SHORT_HALFLIFE,
36
- FeeEstimateHorizon::MED_HALFLIFE,
37
- FeeEstimateHorizon::LONG_HALFLIFE,
38
- };
39
-
40
- std::string StringForFeeEstimateHorizon(FeeEstimateHorizon horizon);
41
-
42
- /* Enumeration of reason for returned fee estimate */
43
- enum class FeeReason {
44
- NONE,
45
- HALF_ESTIMATE,
46
- FULL_ESTIMATE,
47
- DOUBLE_ESTIMATE,
48
- CONSERVATIVE,
49
- MEMPOOL_MIN,
50
- PAYTXFEE,
51
- FALLBACK,
52
- REQUIRED,
53
- };
54
-
55
- /* Used to return detailed information about a feerate bucket */
56
- struct EstimatorBucket
57
- {
58
- double start = -1;
59
- double end = -1;
60
- double withinTarget = 0;
61
- double totalConfirmed = 0;
62
- double inMempool = 0;
63
- double leftMempool = 0;
64
- };
65
-
66
- /* Used to return detailed information about a fee estimate calculation */
67
- struct EstimationResult
68
- {
69
- EstimatorBucket pass;
70
- EstimatorBucket fail;
71
- double decay = 0;
72
- unsigned int scale = 0;
73
- };
74
-
75
- struct FeeCalculation
76
- {
77
- EstimationResult est;
78
- FeeReason reason = FeeReason::NONE;
79
- int desiredTarget = 0;
80
- int returnedTarget = 0;
81
- };
82
-
83
- /** \class CBlockPolicyEstimator
84
- * The BlockPolicyEstimator is used for estimating the feerate needed
85
- * for a transaction to be included in a block within a certain number of
86
- * blocks.
87
- *
88
- * At a high level the algorithm works by grouping transactions into buckets
89
- * based on having similar feerates and then tracking how long it
90
- * takes transactions in the various buckets to be mined. It operates under
91
- * the assumption that in general transactions of higher feerate will be
92
- * included in blocks before transactions of lower feerate. So for
93
- * example if you wanted to know what feerate you should put on a transaction to
94
- * be included in a block within the next 5 blocks, you would start by looking
95
- * at the bucket with the highest feerate transactions and verifying that a
96
- * sufficiently high percentage of them were confirmed within 5 blocks and
97
- * then you would look at the next highest feerate bucket, and so on, stopping at
98
- * the last bucket to pass the test. The average feerate of transactions in this
99
- * bucket will give you an indication of the lowest feerate you can put on a
100
- * transaction and still have a sufficiently high chance of being confirmed
101
- * within your desired 5 blocks.
102
- *
103
- * Here is a brief description of the implementation:
104
- * When a transaction enters the mempool, we track the height of the block chain
105
- * at entry. All further calculations are conducted only on this set of "seen"
106
- * transactions. Whenever a block comes in, we count the number of transactions
107
- * in each bucket and the total amount of feerate paid in each bucket. Then we
108
- * calculate how many blocks Y it took each transaction to be mined. We convert
109
- * from a number of blocks to a number of periods Y' each encompassing "scale"
110
- * blocks. This is tracked in 3 different data sets each up to a maximum
111
- * number of periods. Within each data set we have an array of counters in each
112
- * feerate bucket and we increment all the counters from Y' up to max periods
113
- * representing that a tx was successfully confirmed in less than or equal to
114
- * that many periods. We want to save a history of this information, so at any
115
- * time we have a counter of the total number of transactions that happened in a
116
- * given feerate bucket and the total number that were confirmed in each of the
117
- * periods or less for any bucket. We save this history by keeping an
118
- * exponentially decaying moving average of each one of these stats. This is
119
- * done for a different decay in each of the 3 data sets to keep relevant data
120
- * from different time horizons. Furthermore we also keep track of the number
121
- * unmined (in mempool or left mempool without being included in a block)
122
- * transactions in each bucket and for how many blocks they have been
123
- * outstanding and use both of these numbers to increase the number of transactions
124
- * we've seen in that feerate bucket when calculating an estimate for any number
125
- * of confirmations below the number of blocks they've been outstanding.
126
- *
127
- * We want to be able to estimate feerates that are needed on tx's to be included in
128
- * a certain number of blocks. Every time a block is added to the best chain, this class records
129
- * stats on the transactions included in that block
130
- */
131
- class CBlockPolicyEstimator
132
- {
133
- private:
134
- /** Track confirm delays up to 12 blocks for short horizon */
135
- static constexpr unsigned int SHORT_BLOCK_PERIODS = 12;
136
- static constexpr unsigned int SHORT_SCALE = 1;
137
- /** Track confirm delays up to 48 blocks for medium horizon */
138
- static constexpr unsigned int MED_BLOCK_PERIODS = 24;
139
- static constexpr unsigned int MED_SCALE = 2;
140
- /** Track confirm delays up to 1008 blocks for long horizon */
141
- static constexpr unsigned int LONG_BLOCK_PERIODS = 42;
142
- static constexpr unsigned int LONG_SCALE = 24;
143
- /** Historical estimates that are older than this aren't valid */
144
- static const unsigned int OLDEST_ESTIMATE_HISTORY = 6 * 1008;
145
-
146
- /** Decay of .962 is a half-life of 18 blocks or about 3 hours */
147
- static constexpr double SHORT_DECAY = .962;
148
- /** Decay of .9952 is a half-life of 144 blocks or about 1 day */
149
- static constexpr double MED_DECAY = .9952;
150
- /** Decay of .99931 is a half-life of 1008 blocks or about 1 week */
151
- static constexpr double LONG_DECAY = .99931;
152
-
153
- /** Require greater than 60% of X feerate transactions to be confirmed within Y/2 blocks*/
154
- static constexpr double HALF_SUCCESS_PCT = .6;
155
- /** Require greater than 85% of X feerate transactions to be confirmed within Y blocks*/
156
- static constexpr double SUCCESS_PCT = .85;
157
- /** Require greater than 95% of X feerate transactions to be confirmed within 2 * Y blocks*/
158
- static constexpr double DOUBLE_SUCCESS_PCT = .95;
159
-
160
- /** Require an avg of 0.1 tx in the combined feerate bucket per block to have stat significance */
161
- static constexpr double SUFFICIENT_FEETXS = 0.1;
162
- /** Require an avg of 0.5 tx when using short decay since there are fewer blocks considered*/
163
- static constexpr double SUFFICIENT_TXS_SHORT = 0.5;
164
-
165
- /** Minimum and Maximum values for tracking feerates
166
- * The MIN_BUCKET_FEERATE should just be set to the lowest reasonable feerate we
167
- * might ever want to track. Historically this has been 1000 since it was
168
- * inheriting DEFAULT_MIN_RELAY_TX_FEE and changing it is disruptive as it
169
- * invalidates old estimates files. So leave it at 1000 unless it becomes
170
- * necessary to lower it, and then lower it substantially.
171
- */
172
- static constexpr double MIN_BUCKET_FEERATE = 1000;
173
- static constexpr double MAX_BUCKET_FEERATE = 1e7;
174
-
175
- /** Spacing of FeeRate buckets
176
- * We have to lump transactions into buckets based on feerate, but we want to be able
177
- * to give accurate estimates over a large range of potential feerates
178
- * Therefore it makes sense to exponentially space the buckets
179
- */
180
- static constexpr double FEE_SPACING = 1.05;
181
-
182
- public:
183
- /** Create new BlockPolicyEstimator and initialize stats tracking classes with default values */
184
- CBlockPolicyEstimator();
185
- ~CBlockPolicyEstimator();
186
-
187
- /** Process all the transactions that have been included in a block */
188
- void processBlock(unsigned int nBlockHeight,
189
- std::vector<const CTxMemPoolEntry*>& entries)
190
- EXCLUSIVE_LOCKS_REQUIRED(!m_cs_fee_estimator);
191
-
192
- /** Process a transaction accepted to the mempool*/
193
- void processTransaction(const CTxMemPoolEntry& entry, bool validFeeEstimate)
194
- EXCLUSIVE_LOCKS_REQUIRED(!m_cs_fee_estimator);
195
-
196
- /** Remove a transaction from the mempool tracking stats*/
197
- bool removeTx(uint256 hash, bool inBlock)
198
- EXCLUSIVE_LOCKS_REQUIRED(!m_cs_fee_estimator);
199
-
200
- /** DEPRECATED. Return a feerate estimate */
201
- CFeeRate estimateFee(int confTarget) const
202
- EXCLUSIVE_LOCKS_REQUIRED(!m_cs_fee_estimator);
203
-
204
- /** Estimate feerate needed to get be included in a block within confTarget
205
- * blocks. If no answer can be given at confTarget, return an estimate at
206
- * the closest target where one can be given. 'conservative' estimates are
207
- * valid over longer time horizons also.
208
- */
209
- CFeeRate estimateSmartFee(int confTarget, FeeCalculation *feeCalc, bool conservative) const
210
- EXCLUSIVE_LOCKS_REQUIRED(!m_cs_fee_estimator);
211
-
212
- /** Return a specific fee estimate calculation with a given success
213
- * threshold and time horizon, and optionally return detailed data about
214
- * calculation
215
- */
216
- CFeeRate estimateRawFee(int confTarget, double successThreshold, FeeEstimateHorizon horizon,
217
- EstimationResult* result = nullptr) const
218
- EXCLUSIVE_LOCKS_REQUIRED(!m_cs_fee_estimator);
219
-
220
- /** Write estimation data to a file */
221
- bool Write(CAutoFile& fileout) const
222
- EXCLUSIVE_LOCKS_REQUIRED(!m_cs_fee_estimator);
223
-
224
- /** Read estimation data from a file */
225
- bool Read(CAutoFile& filein)
226
- EXCLUSIVE_LOCKS_REQUIRED(!m_cs_fee_estimator);
227
-
228
- /** Empty mempool transactions on shutdown to record failure to confirm for txs still in mempool */
229
- void FlushUnconfirmed()
230
- EXCLUSIVE_LOCKS_REQUIRED(!m_cs_fee_estimator);
231
-
232
- /** Calculation of highest target that estimates are tracked for */
233
- unsigned int HighestTargetTracked(FeeEstimateHorizon horizon) const
234
- EXCLUSIVE_LOCKS_REQUIRED(!m_cs_fee_estimator);
235
-
236
- /** Drop still unconfirmed transactions and record current estimations, if the fee estimation file is present. */
237
- void Flush()
238
- EXCLUSIVE_LOCKS_REQUIRED(!m_cs_fee_estimator);
239
-
240
- private:
241
- mutable Mutex m_cs_fee_estimator;
242
-
243
- unsigned int nBestSeenHeight GUARDED_BY(m_cs_fee_estimator);
244
- unsigned int firstRecordedHeight GUARDED_BY(m_cs_fee_estimator);
245
- unsigned int historicalFirst GUARDED_BY(m_cs_fee_estimator);
246
- unsigned int historicalBest GUARDED_BY(m_cs_fee_estimator);
247
-
248
- struct TxStatsInfo
249
- {
250
- unsigned int blockHeight;
251
- unsigned int bucketIndex;
252
- TxStatsInfo() : blockHeight(0), bucketIndex(0) {}
253
- };
254
-
255
- // map of txids to information about that transaction
256
- std::map<uint256, TxStatsInfo> mapMemPoolTxs GUARDED_BY(m_cs_fee_estimator);
257
-
258
- /** Classes to track historical data on transaction confirmations */
259
- std::unique_ptr<TxConfirmStats> feeStats PT_GUARDED_BY(m_cs_fee_estimator);
260
- std::unique_ptr<TxConfirmStats> shortStats PT_GUARDED_BY(m_cs_fee_estimator);
261
- std::unique_ptr<TxConfirmStats> longStats PT_GUARDED_BY(m_cs_fee_estimator);
262
-
263
- unsigned int trackedTxs GUARDED_BY(m_cs_fee_estimator);
264
- unsigned int untrackedTxs GUARDED_BY(m_cs_fee_estimator);
265
-
266
- std::vector<double> buckets GUARDED_BY(m_cs_fee_estimator); // The upper-bound of the range for the bucket (inclusive)
267
- std::map<double, unsigned int> bucketMap GUARDED_BY(m_cs_fee_estimator); // Map of bucket upper-bound to index into all vectors by bucket
268
-
269
- /** Process a transaction confirmed in a block*/
270
- bool processBlockTx(unsigned int nBlockHeight, const CTxMemPoolEntry* entry) EXCLUSIVE_LOCKS_REQUIRED(m_cs_fee_estimator);
271
-
272
- /** Helper for estimateSmartFee */
273
- double estimateCombinedFee(unsigned int confTarget, double successThreshold, bool checkShorterHorizon, EstimationResult *result) const EXCLUSIVE_LOCKS_REQUIRED(m_cs_fee_estimator);
274
- /** Helper for estimateSmartFee */
275
- double estimateConservativeFee(unsigned int doubleTarget, EstimationResult *result) const EXCLUSIVE_LOCKS_REQUIRED(m_cs_fee_estimator);
276
- /** Number of blocks of data recorded while fee estimates have been running */
277
- unsigned int BlockSpan() const EXCLUSIVE_LOCKS_REQUIRED(m_cs_fee_estimator);
278
- /** Number of blocks of recorded fee estimate data represented in saved data file */
279
- unsigned int HistoricalBlockSpan() const EXCLUSIVE_LOCKS_REQUIRED(m_cs_fee_estimator);
280
- /** Calculation of highest target that reasonable estimate can be provided for */
281
- unsigned int MaxUsableEstimate() const EXCLUSIVE_LOCKS_REQUIRED(m_cs_fee_estimator);
282
-
283
- /** A non-thread-safe helper for the removeTx function */
284
- bool _removeTx(const uint256& hash, bool inBlock)
285
- EXCLUSIVE_LOCKS_REQUIRED(m_cs_fee_estimator);
286
- };
287
-
288
- class FeeFilterRounder
289
- {
290
- private:
291
- static constexpr double MAX_FILTER_FEERATE = 1e7;
292
- /** FEE_FILTER_SPACING is just used to provide some quantization of fee
293
- * filter results. Historically it reused FEE_SPACING, but it is completely
294
- * unrelated, and was made a separate constant so the two concepts are not
295
- * tied together */
296
- static constexpr double FEE_FILTER_SPACING = 1.1;
297
-
298
- public:
299
- /** Create new FeeFilterRounder */
300
- explicit FeeFilterRounder(const CFeeRate& minIncrementalFee);
301
-
302
- /** Quantize a minimum fee for privacy purpose before broadcast. Not thread-safe due to use of FastRandomContext */
303
- CAmount round(CAmount currentMinFee);
304
-
305
- private:
306
- std::set<double> feeset;
307
- FastRandomContext insecure_rand;
308
- };
309
-
310
- #endif // BITCOIN_POLICY_FEES_H
src/policy/policy.cpp CHANGED
@@ -9,52 +9,9 @@
9
9
 
10
10
  #include <consensus/validation.h>
11
11
  #include <coins.h>
12
+ #include <kernel.h>
12
13
  #include <span.h>
13
14
 
14
- CAmount GetDustThreshold(const CTxOut& txout, const CFeeRate& dustRelayFeeIn)
15
- {
16
- // "Dust" is defined in terms of dustRelayFee,
17
- // which has units satoshis-per-kilobyte.
18
- // If you'd pay more in fees than the value of the output
19
- // to spend something, then we consider it dust.
20
- // A typical spendable non-segwit txout is 34 bytes big, and will
21
- // need a CTxIn of at least 148 bytes to spend:
22
- // so dust is a spendable txout less than
23
- // 182*dustRelayFee/1000 (in satoshis).
24
- // 546 satoshis at the default rate of 3000 sat/kvB.
25
- // A typical spendable segwit P2WPKH txout is 31 bytes big, and will
26
- // need a CTxIn of at least 67 bytes to spend:
27
- // so dust is a spendable txout less than
28
- // 98*dustRelayFee/1000 (in satoshis).
29
- // 294 satoshis at the default rate of 3000 sat/kvB.
30
- if (txout.scriptPubKey.IsUnspendable())
31
- return 0;
32
-
33
- size_t nSize = GetSerializeSize(txout);
34
- int witnessversion = 0;
35
- std::vector<unsigned char> witnessprogram;
36
-
37
- // Note this computation is for spending a Segwit v0 P2WPKH output (a 33 bytes
38
- // public key + an ECDSA signature). For Segwit v1 Taproot outputs the minimum
39
- // satisfaction is lower (a single BIP340 signature) but this computation was
40
- // kept to not further reduce the dust level.
41
- // See discussion in https://github.com/bitcoin/bitcoin/pull/22779 for details.
42
- if (txout.scriptPubKey.IsWitnessProgram(witnessversion, witnessprogram)) {
43
- // sum the sizes of the parts of a transaction input
44
- // with 75% segwit discount applied to the script size.
45
- nSize += (32 + 4 + 1 + (107 / WITNESS_SCALE_FACTOR) + 4);
46
- } else {
47
- nSize += (32 + 4 + 1 + 107 + 4); // the 148 mentioned above
48
- }
49
-
50
- return dustRelayFeeIn.GetFee(nSize);
51
- }
52
-
53
- bool IsDust(const CTxOut& txout, const CFeeRate& dustRelayFeeIn)
54
- {
55
- return (txout.nValue < GetDustThreshold(txout, dustRelayFeeIn));
56
- }
57
-
58
15
  bool IsStandard(const CScript& scriptPubKey, TxoutType& whichType)
59
16
  {
60
17
  std::vector<std::vector<unsigned char> > vSolutions;
@@ -78,7 +35,7 @@ bool IsStandard(const CScript& scriptPubKey, TxoutType& whichType)
78
35
  return true;
79
36
  }
80
37
 
81
- bool IsStandardTx(const CTransaction& tx, bool permit_bare_multisig, const CFeeRate& dust_relay_fee, std::string& reason)
38
+ bool IsStandardTx(const CTransaction& tx, bool permit_bare_multisig, std::string& reason)
82
39
  {
83
40
  if (tx.nVersion > TX_MAX_STANDARD_VERSION || tx.nVersion < 1) {
84
41
  reason = "version";
@@ -128,9 +85,6 @@ bool IsStandardTx(const CTransaction& tx, bool permit_bare_multisig, const CFeeR
128
85
  else if ((whichType == TxoutType::MULTISIG) && (!permit_bare_multisig)) {
129
86
  reason = "bare-multisig";
130
87
  return false;
131
- } else if (IsDust(txout, dust_relay_fee)) {
132
- reason = "dust";
133
- return false;
134
88
  }
135
89
  }
136
90
 
src/policy/policy.h CHANGED
@@ -7,7 +7,6 @@
7
7
  #define BITCOIN_POLICY_POLICY_H
8
8
 
9
9
  #include <consensus/consensus.h>
10
- #include <policy/feerate.h>
11
10
  #include <script/interpreter.h>
12
11
  #include <script/standard.h>
13
12
 
@@ -18,8 +17,6 @@ class CTxOut;
18
17
 
19
18
  /** Default for -blockmaxweight, which controls the range of block weights the mining code will create **/
20
19
  static const unsigned int DEFAULT_BLOCK_MAX_WEIGHT = MAX_BLOCK_WEIGHT - 4000;
21
- /** Default for -blockmintxfee, which sets the minimum feerate for a transaction in blocks created by mining code **/
22
- static const unsigned int DEFAULT_BLOCK_MIN_TX_FEE = 1000;
23
20
  /** The maximum weight for transactions we're willing to relay/mine */
24
21
  static const unsigned int MAX_STANDARD_TX_WEIGHT = 400000;
25
22
  /** The minimum non-witness size for transactions we're willing to relay/mine (1 segwit input + 1 P2WPKH output = 82 bytes) */
@@ -30,8 +27,6 @@ static const unsigned int MAX_P2SH_SIGOPS = 15;
30
27
  static const unsigned int MAX_STANDARD_TX_SIGOPS_COST = MAX_BLOCK_SIGOPS_COST/5;
31
28
  /** Default for -maxmempool, maximum megabytes of mempool memory usage */
32
29
  static const unsigned int DEFAULT_MAX_MEMPOOL_SIZE = 300;
33
- /** Default for -incrementalrelayfee, which sets the minimum feerate increase for mempool limiting or BIP 125 replacement **/
34
- static const unsigned int DEFAULT_INCREMENTAL_RELAY_FEE = 1000;
35
30
  /** Default for -bytespersigop */
36
31
  static const unsigned int DEFAULT_BYTES_PER_SIGOP = 20;
37
32
  /** Default for -permitbaremultisig */
@@ -46,12 +41,6 @@ static const unsigned int MAX_STANDARD_TAPSCRIPT_STACK_ITEM_SIZE = 80;
46
41
  static const unsigned int MAX_STANDARD_P2WSH_SCRIPT_SIZE = 3600;
47
42
  /** The maximum size of a standard ScriptSig */
48
43
  static const unsigned int MAX_STANDARD_SCRIPTSIG_SIZE = 1650;
49
- /** Min feerate for defining dust. Historically this has been based on the
50
- * minRelayTxFee, however changing the dust limit changes which transactions are
51
- * standard and should be done with care and ideally rarely. It makes sense to
52
- * only increase the dust limit after prior releases were already not creating
53
- * outputs below the new threshold */
54
- static const unsigned int DUST_RELAY_TX_FEE = 3000;
55
44
  /**
56
45
  * Standard script verification flags that standard transactions will comply
57
46
  * with. However scripts violating these flags may still be present in valid
@@ -73,7 +62,6 @@ static constexpr unsigned int STANDARD_SCRIPT_VERIFY_FLAGS = MANDATORY_SCRIPT_VE
73
62
  SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM |
74
63
  SCRIPT_VERIFY_WITNESS_PUBKEYTYPE |
75
64
  SCRIPT_VERIFY_CONST_SCRIPTCODE |
76
- SCRIPT_VERIFY_TAPROOT |
77
65
  SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_TAPROOT_VERSION |
78
66
  SCRIPT_VERIFY_DISCOURAGE_OP_SUCCESS |
79
67
  SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_PUBKEYTYPE;
@@ -85,23 +73,19 @@ static constexpr unsigned int STANDARD_NOT_MANDATORY_VERIFY_FLAGS = STANDARD_SCR
85
73
  static constexpr unsigned int STANDARD_LOCKTIME_VERIFY_FLAGS = LOCKTIME_VERIFY_SEQUENCE |
86
74
  LOCKTIME_MEDIAN_TIME_PAST;
87
75
 
88
- CAmount GetDustThreshold(const CTxOut& txout, const CFeeRate& dustRelayFee);
89
-
90
- bool IsDust(const CTxOut& txout, const CFeeRate& dustRelayFee);
91
-
92
76
  bool IsStandard(const CScript& scriptPubKey, TxoutType& whichType);
93
77
 
94
78
 
95
79
  // Changing the default transaction version requires a two step process: first
96
80
  // adapting relay policy by bumping TX_MAX_STANDARD_VERSION, and then later
97
81
  // allowing the new transaction version in the wallet/RPC.
98
- static constexpr decltype(CTransaction::nVersion) TX_MAX_STANDARD_VERSION{2};
82
+ static constexpr decltype(CTransaction::nVersion) TX_MAX_STANDARD_VERSION{3};
99
83
 
100
84
  /**
101
85
  * Check for standard transaction types
102
86
  * @return True if all outputs (scriptPubKeys) use only standard transaction forms
103
87
  */
104
- bool IsStandardTx(const CTransaction& tx, bool permit_bare_multisig, const CFeeRate& dust_relay_fee, std::string& reason);
88
+ bool IsStandardTx(const CTransaction& tx, bool permit_bare_multisig, std::string& reason);
105
89
  /**
106
90
  * Check for standard transaction types
107
91
  * @param[in] mapInputs Map of previous transactions that have outputs we're spending
src/policy/rbf.cpp DELETED
@@ -1,176 +0,0 @@
1
- // Copyright (c) 2016-2021 The Bitcoin Core developers
2
- // Distributed under the MIT software license, see the accompanying
3
- // file COPYING or http://www.opensource.org/licenses/mit-license.php.
4
-
5
- #include <policy/rbf.h>
6
-
7
- #include <policy/settings.h>
8
- #include <tinyformat.h>
9
- #include <util/moneystr.h>
10
- #include <util/rbf.h>
11
-
12
- RBFTransactionState IsRBFOptIn(const CTransaction& tx, const CTxMemPool& pool)
13
- {
14
- AssertLockHeld(pool.cs);
15
-
16
- CTxMemPool::setEntries ancestors;
17
-
18
- // First check the transaction itself.
19
- if (SignalsOptInRBF(tx)) {
20
- return RBFTransactionState::REPLACEABLE_BIP125;
21
- }
22
-
23
- // If this transaction is not in our mempool, then we can't be sure
24
- // we will know about all its inputs.
25
- if (!pool.exists(GenTxid::Txid(tx.GetHash()))) {
26
- return RBFTransactionState::UNKNOWN;
27
- }
28
-
29
- // If all the inputs have nSequence >= maxint-1, it still might be
30
- // signaled for RBF if any unconfirmed parents have signaled.
31
- uint64_t noLimit = std::numeric_limits<uint64_t>::max();
32
- std::string dummy;
33
- CTxMemPoolEntry entry = *pool.mapTx.find(tx.GetHash());
34
- pool.CalculateMemPoolAncestors(entry, ancestors, noLimit, noLimit, noLimit, noLimit, dummy, false);
35
-
36
- for (CTxMemPool::txiter it : ancestors) {
37
- if (SignalsOptInRBF(it->GetTx())) {
38
- return RBFTransactionState::REPLACEABLE_BIP125;
39
- }
40
- }
41
- return RBFTransactionState::FINAL;
42
- }
43
-
44
- RBFTransactionState IsRBFOptInEmptyMempool(const CTransaction& tx)
45
- {
46
- // If we don't have a local mempool we can only check the transaction itself.
47
- return SignalsOptInRBF(tx) ? RBFTransactionState::REPLACEABLE_BIP125 : RBFTransactionState::UNKNOWN;
48
- }
49
-
50
- std::optional<std::string> GetEntriesForConflicts(const CTransaction& tx,
51
- CTxMemPool& pool,
52
- const CTxMemPool::setEntries& iters_conflicting,
53
- CTxMemPool::setEntries& all_conflicts)
54
- {
55
- AssertLockHeld(pool.cs);
56
- const uint256 txid = tx.GetHash();
57
- uint64_t nConflictingCount = 0;
58
- for (const auto& mi : iters_conflicting) {
59
- nConflictingCount += mi->GetCountWithDescendants();
60
- // BIP125 Rule #5: don't consider replacing more than MAX_BIP125_REPLACEMENT_CANDIDATES
61
- // entries from the mempool. This potentially overestimates the number of actual
62
- // descendants (i.e. if multiple conflicts share a descendant, it will be counted multiple
63
- // times), but we just want to be conservative to avoid doing too much work.
64
- if (nConflictingCount > MAX_BIP125_REPLACEMENT_CANDIDATES) {
65
- return strprintf("rejecting replacement %s; too many potential replacements (%d > %d)\n",
66
- txid.ToString(),
67
- nConflictingCount,
68
- MAX_BIP125_REPLACEMENT_CANDIDATES);
69
- }
70
- }
71
- // Calculate the set of all transactions that would have to be evicted.
72
- for (CTxMemPool::txiter it : iters_conflicting) {
73
- pool.CalculateDescendants(it, all_conflicts);
74
- }
75
- return std::nullopt;
76
- }
77
-
78
- std::optional<std::string> HasNoNewUnconfirmed(const CTransaction& tx,
79
- const CTxMemPool& pool,
80
- const CTxMemPool::setEntries& iters_conflicting)
81
- {
82
- AssertLockHeld(pool.cs);
83
- std::set<uint256> parents_of_conflicts;
84
- for (const auto& mi : iters_conflicting) {
85
- for (const CTxIn& txin : mi->GetTx().vin) {
86
- parents_of_conflicts.insert(txin.prevout.hash);
87
- }
88
- }
89
-
90
- for (unsigned int j = 0; j < tx.vin.size(); j++) {
91
- // BIP125 Rule #2: We don't want to accept replacements that require low feerate junk to be
92
- // mined first. Ideally we'd keep track of the ancestor feerates and make the decision
93
- // based on that, but for now requiring all new inputs to be confirmed works.
94
- //
95
- // Note that if you relax this to make RBF a little more useful, this may break the
96
- // CalculateMempoolAncestors RBF relaxation which subtracts the conflict count/size from the
97
- // descendant limit.
98
- if (!parents_of_conflicts.count(tx.vin[j].prevout.hash)) {
99
- // Rather than check the UTXO set - potentially expensive - it's cheaper to just check
100
- // if the new input refers to a tx that's in the mempool.
101
- if (pool.exists(GenTxid::Txid(tx.vin[j].prevout.hash))) {
102
- return strprintf("replacement %s adds unconfirmed input, idx %d",
103
- tx.GetHash().ToString(), j);
104
- }
105
- }
106
- }
107
- return std::nullopt;
108
- }
109
-
110
- std::optional<std::string> EntriesAndTxidsDisjoint(const CTxMemPool::setEntries& ancestors,
111
- const std::set<uint256>& direct_conflicts,
112
- const uint256& txid)
113
- {
114
- for (CTxMemPool::txiter ancestorIt : ancestors) {
115
- const uint256& hashAncestor = ancestorIt->GetTx().GetHash();
116
- if (direct_conflicts.count(hashAncestor)) {
117
- return strprintf("%s spends conflicting transaction %s",
118
- txid.ToString(),
119
- hashAncestor.ToString());
120
- }
121
- }
122
- return std::nullopt;
123
- }
124
-
125
- std::optional<std::string> PaysMoreThanConflicts(const CTxMemPool::setEntries& iters_conflicting,
126
- CFeeRate replacement_feerate,
127
- const uint256& txid)
128
- {
129
- for (const auto& mi : iters_conflicting) {
130
- // Don't allow the replacement to reduce the feerate of the mempool.
131
- //
132
- // We usually don't want to accept replacements with lower feerates than what they replaced
133
- // as that would lower the feerate of the next block. Requiring that the feerate always be
134
- // increased is also an easy-to-reason about way to prevent DoS attacks via replacements.
135
- //
136
- // We only consider the feerates of transactions being directly replaced, not their indirect
137
- // descendants. While that does mean high feerate children are ignored when deciding whether
138
- // or not to replace, we do require the replacement to pay more overall fees too, mitigating
139
- // most cases.
140
- CFeeRate original_feerate(mi->GetModifiedFee(), mi->GetTxSize());
141
- if (replacement_feerate <= original_feerate) {
142
- return strprintf("rejecting replacement %s; new feerate %s <= old feerate %s",
143
- txid.ToString(),
144
- replacement_feerate.ToString(),
145
- original_feerate.ToString());
146
- }
147
- }
148
- return std::nullopt;
149
- }
150
-
151
- std::optional<std::string> PaysForRBF(CAmount original_fees,
152
- CAmount replacement_fees,
153
- size_t replacement_vsize,
154
- CFeeRate relay_fee,
155
- const uint256& txid)
156
- {
157
- // BIP125 Rule #3: The replacement fees must be greater than or equal to fees of the
158
- // transactions it replaces, otherwise the bandwidth used by those conflicting transactions
159
- // would not be paid for.
160
- if (replacement_fees < original_fees) {
161
- return strprintf("rejecting replacement %s, less fees than conflicting txs; %s < %s",
162
- txid.ToString(), FormatMoney(replacement_fees), FormatMoney(original_fees));
163
- }
164
-
165
- // BIP125 Rule #4: The new transaction must pay for its own bandwidth. Otherwise, we have a DoS
166
- // vector where attackers can cause a transaction to be replaced (and relayed) repeatedly by
167
- // increasing the fee by tiny amounts.
168
- CAmount additional_fees = replacement_fees - original_fees;
169
- if (additional_fees < relay_fee.GetFee(replacement_vsize)) {
170
- return strprintf("rejecting replacement %s, not enough additional fees to relay; %s < %s",
171
- txid.ToString(),
172
- FormatMoney(additional_fees),
173
- FormatMoney(relay_fee.GetFee(replacement_vsize)));
174
- }
175
- return std::nullopt;
176
- }
src/policy/rbf.h DELETED
@@ -1,102 +0,0 @@
1
- // Copyright (c) 2016-2021 The Bitcoin Core developers
2
- // Distributed under the MIT software license, see the accompanying
3
- // file COPYING or http://www.opensource.org/licenses/mit-license.php.
4
-
5
- #ifndef BITCOIN_POLICY_RBF_H
6
- #define BITCOIN_POLICY_RBF_H
7
-
8
- #include <primitives/transaction.h>
9
- #include <txmempool.h>
10
- #include <uint256.h>
11
-
12
- #include <optional>
13
- #include <string>
14
-
15
- /** Maximum number of transactions that can be replaced by BIP125 RBF (Rule #5). This includes all
16
- * mempool conflicts and their descendants. */
17
- static constexpr uint32_t MAX_BIP125_REPLACEMENT_CANDIDATES{100};
18
-
19
- /** The rbf state of unconfirmed transactions */
20
- enum class RBFTransactionState {
21
- /** Unconfirmed tx that does not signal rbf and is not in the mempool */
22
- UNKNOWN,
23
- /** Either this tx or a mempool ancestor signals rbf */
24
- REPLACEABLE_BIP125,
25
- /** Neither this tx nor a mempool ancestor signals rbf */
26
- FINAL,
27
- };
28
-
29
- /**
30
- * Determine whether an unconfirmed transaction is signaling opt-in to RBF
31
- * according to BIP 125
32
- * This involves checking sequence numbers of the transaction, as well
33
- * as the sequence numbers of all in-mempool ancestors.
34
- *
35
- * @param tx The unconfirmed transaction
36
- * @param pool The mempool, which may contain the tx
37
- *
38
- * @return The rbf state
39
- */
40
- RBFTransactionState IsRBFOptIn(const CTransaction& tx, const CTxMemPool& pool) EXCLUSIVE_LOCKS_REQUIRED(pool.cs);
41
- RBFTransactionState IsRBFOptInEmptyMempool(const CTransaction& tx);
42
-
43
- /** Get all descendants of iters_conflicting. Also enforce BIP125 Rule #5, "The number of original
44
- * transactions to be replaced and their descendant transactions which will be evicted from the
45
- * mempool must not exceed a total of 100 transactions." Quit as early as possible. There cannot be
46
- * more than MAX_BIP125_REPLACEMENT_CANDIDATES potential entries.
47
- * @param[in] iters_conflicting The set of iterators to mempool entries.
48
- * @param[out] all_conflicts Populated with all the mempool entries that would be replaced,
49
- * which includes descendants of iters_conflicting. Not cleared at
50
- * the start; any existing mempool entries will remain in the set.
51
- * @returns an error message if Rule #5 is broken, otherwise a std::nullopt.
52
- */
53
- std::optional<std::string> GetEntriesForConflicts(const CTransaction& tx, CTxMemPool& pool,
54
- const CTxMemPool::setEntries& iters_conflicting,
55
- CTxMemPool::setEntries& all_conflicts)
56
- EXCLUSIVE_LOCKS_REQUIRED(pool.cs);
57
-
58
- /** BIP125 Rule #2: "The replacement transaction may only include an unconfirmed input if that input
59
- * was included in one of the original transactions."
60
- * @returns error message if Rule #2 is broken, otherwise std::nullopt. */
61
- std::optional<std::string> HasNoNewUnconfirmed(const CTransaction& tx, const CTxMemPool& pool,
62
- const CTxMemPool::setEntries& iters_conflicting)
63
- EXCLUSIVE_LOCKS_REQUIRED(pool.cs);
64
-
65
- /** Check the intersection between two sets of transactions (a set of mempool entries and a set of
66
- * txids) to make sure they are disjoint.
67
- * @param[in] ancestors Set of mempool entries corresponding to ancestors of the
68
- * replacement transactions.
69
- * @param[in] direct_conflicts Set of txids corresponding to the mempool conflicts
70
- * (candidates to be replaced).
71
- * @param[in] txid Transaction ID, included in the error message if violation occurs.
72
- * @returns error message if the sets intersect, std::nullopt if they are disjoint.
73
- */
74
- std::optional<std::string> EntriesAndTxidsDisjoint(const CTxMemPool::setEntries& ancestors,
75
- const std::set<uint256>& direct_conflicts,
76
- const uint256& txid);
77
-
78
- /** Check that the feerate of the replacement transaction(s) is higher than the feerate of each
79
- * of the transactions in iters_conflicting.
80
- * @param[in] iters_conflicting The set of mempool entries.
81
- * @returns error message if fees insufficient, otherwise std::nullopt.
82
- */
83
- std::optional<std::string> PaysMoreThanConflicts(const CTxMemPool::setEntries& iters_conflicting,
84
- CFeeRate replacement_feerate, const uint256& txid);
85
-
86
- /** Enforce BIP125 Rule #3 "The replacement transaction pays an absolute fee of at least the sum
87
- * paid by the original transactions." Enforce BIP125 Rule #4 "The replacement transaction must also
88
- * pay for its own bandwidth at or above the rate set by the node's minimum relay fee setting."
89
- * @param[in] original_fees Total modified fees of original transaction(s).
90
- * @param[in] replacement_fees Total modified fees of replacement transaction(s).
91
- * @param[in] replacement_vsize Total virtual size of replacement transaction(s).
92
- * @param[in] relay_fee The node's minimum feerate for transaction relay.
93
- * @param[in] txid Transaction ID, included in the error message if violation occurs.
94
- * @returns error string if fees are insufficient, otherwise std::nullopt.
95
- */
96
- std::optional<std::string> PaysForRBF(CAmount original_fees,
97
- CAmount replacement_fees,
98
- size_t replacement_vsize,
99
- CFeeRate relay_fee,
100
- const uint256& txid);
101
-
102
- #endif // BITCOIN_POLICY_RBF_H
src/policy/settings.cpp CHANGED
@@ -5,10 +5,7 @@
5
5
 
6
6
  #include <policy/settings.h>
7
7
 
8
- #include <policy/feerate.h>
9
8
  #include <policy/policy.h>
10
9
 
11
10
  bool fIsBareMultisigStd = DEFAULT_PERMIT_BAREMULTISIG;
12
- CFeeRate incrementalRelayFee = CFeeRate(DEFAULT_INCREMENTAL_RELAY_FEE);
13
- CFeeRate dustRelayFee = CFeeRate(DUST_RELAY_TX_FEE);
14
11
  unsigned int nBytesPerSigOp = DEFAULT_BYTES_PER_SIGOP;
src/policy/settings.h CHANGED
@@ -8,18 +8,15 @@
8
8
 
9
9
  #include <policy/policy.h>
10
10
 
11
- class CFeeRate;
12
11
  class CTransaction;
13
12
 
14
13
  // Policy settings which are configurable at runtime.
15
- extern CFeeRate incrementalRelayFee;
16
- extern CFeeRate dustRelayFee;
17
14
  extern unsigned int nBytesPerSigOp;
18
15
  extern bool fIsBareMultisigStd;
19
16
 
20
17
  static inline bool IsStandardTx(const CTransaction& tx, std::string& reason)
21
18
  {
22
- return IsStandardTx(tx, ::fIsBareMultisigStd, ::dustRelayFee, reason);
19
+ return IsStandardTx(tx, ::fIsBareMultisigStd, reason);
23
20
  }
24
21
 
25
22
  static inline int64_t GetVirtualTransactionSize(int64_t weight, int64_t sigop_cost)
src/pow.cpp CHANGED
@@ -10,63 +10,53 @@
10
10
  #include <primitives/block.h>
11
11
  #include <uint256.h>
12
12
 
13
- unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHeader *pblock, const Consensus::Params& params)
13
+ #include <bignum.h>
14
+ #include <chainparams.h>
15
+ #include <kernel.h>
16
+
17
+ unsigned int GetNextTargetRequired(const CBlockIndex* pindexLast, bool fProofOfStake, const Consensus::Params& params)
14
18
  {
15
- assert(pindexLast != nullptr);
16
- unsigned int nProofOfWorkLimit = UintToArith256(params.powLimit).GetCompact();
17
-
18
- // Only change once per difficulty adjustment interval
19
- if ((pindexLast->nHeight+1) % params.DifficultyAdjustmentInterval() != 0)
20
- {
21
- if (params.fPowAllowMinDifficultyBlocks)
22
- {
23
- // Special difficulty rule for testnet:
24
- // If the new block's timestamp is more than 2* 10 minutes
25
- // then allow mining of a min-difficulty block.
26
- if (pblock->GetBlockTime() > pindexLast->GetBlockTime() + params.nPowTargetSpacing*2)
27
- return nProofOfWorkLimit;
28
- else
29
- {
30
- // Return the last non-special-min-difficulty-rules-block
31
- const CBlockIndex* pindex = pindexLast;
32
- while (pindex->pprev && pindex->nHeight % params.DifficultyAdjustmentInterval() != 0 && pindex->nBits == nProofOfWorkLimit)
33
- pindex = pindex->pprev;
34
- return pindex->nBits;
19
+ if (pindexLast == nullptr)
20
+ return UintToArith256(params.powLimit).GetCompact(); // genesis block
21
+
22
+ const CBlockIndex* pindexPrev = GetLastBlockIndex(pindexLast, fProofOfStake);
23
+ if (pindexPrev->pprev == nullptr)
24
+ return UintToArith256(params.bnInitialHashTarget).GetCompact(); // first block
25
+ const CBlockIndex* pindexPrevPrev = GetLastBlockIndex(pindexPrev->pprev, fProofOfStake);
26
+ if (pindexPrevPrev->pprev == nullptr)
27
+ return UintToArith256(params.bnInitialHashTarget).GetCompact(); // second block
28
+
29
+ int64_t nActualSpacing = pindexPrev->GetBlockTime() - pindexPrevPrev->GetBlockTime();
30
+
31
+ // rfc20
32
+ int64_t nHypotheticalSpacing = pindexLast->GetBlockTime() - pindexPrev->GetBlockTime();
33
+ if (!fProofOfStake && IsProtocolV12(pindexPrev) && (nHypotheticalSpacing > nActualSpacing))
34
+ nActualSpacing = nHypotheticalSpacing;
35
+
36
+ // peercoin: target change every block
37
+ // peercoin: retarget with exponential moving toward target spacing
38
+ CBigNum bnNew;
39
+ bnNew.SetCompact(pindexPrev->nBits);
40
+ if (Params().NetworkIDString() != CBaseChainParams::REGTEST) {
41
+ int64_t nTargetSpacing;
42
+
43
+ if (fProofOfStake) {
44
+ nTargetSpacing = params.nStakeTargetSpacing;
45
+ } else {
46
+ if (IsProtocolV09(pindexLast->nTime)) {
47
+ nTargetSpacing = params.nStakeTargetSpacing * 6;
48
+ } else {
49
+ nTargetSpacing = std::min(params.nTargetSpacingWorkMax, params.nStakeTargetSpacing * (1 + pindexLast->nHeight - pindexPrev->nHeight));
35
50
  }
36
51
  }
37
- return pindexLast->nBits;
38
- }
39
-
40
- // Go back by what we want to be 14 days worth of blocks
41
- int nHeightFirst = pindexLast->nHeight - (params.DifficultyAdjustmentInterval()-1);
42
- assert(nHeightFirst >= 0);
43
- const CBlockIndex* pindexFirst = pindexLast->GetAncestor(nHeightFirst);
44
- assert(pindexFirst);
45
52
 
46
- return CalculateNextWorkRequired(pindexLast, pindexFirst->GetBlockTime(), params);
47
- }
53
+ int64_t nInterval = params.nTargetTimespan / nTargetSpacing;
54
+ bnNew *= ((nInterval - 1) * nTargetSpacing + nActualSpacing + nActualSpacing);
55
+ bnNew /= ((nInterval + 1) * nTargetSpacing);
56
+ }
48
57
 
49
- unsigned int CalculateNextWorkRequired(const CBlockIndex* pindexLast, int64_t nFirstBlockTime, const Consensus::Params& params)
50
- {
51
- if (params.fPowNoRetargeting)
52
- return pindexLast->nBits;
53
-
54
- // Limit adjustment step
55
- int64_t nActualTimespan = pindexLast->GetBlockTime() - nFirstBlockTime;
56
- if (nActualTimespan < params.nPowTargetTimespan/4)
57
- nActualTimespan = params.nPowTargetTimespan/4;
58
- if (nActualTimespan > params.nPowTargetTimespan*4)
59
- nActualTimespan = params.nPowTargetTimespan*4;
60
-
61
- // Retarget
62
- const arith_uint256 bnPowLimit = UintToArith256(params.powLimit);
63
- arith_uint256 bnNew;
64
- bnNew.SetCompact(pindexLast->nBits);
65
- bnNew *= nActualTimespan;
66
- bnNew /= params.nPowTargetTimespan;
67
-
68
- if (bnNew > bnPowLimit)
69
- bnNew = bnPowLimit;
58
+ if (bnNew > CBigNum(params.powLimit))
59
+ bnNew = CBigNum(params.powLimit);
70
60
 
71
61
  return bnNew.GetCompact();
72
62
  }
src/pow.h CHANGED
@@ -14,8 +14,7 @@ class CBlockHeader;
14
14
  class CBlockIndex;
15
15
  class uint256;
16
16
 
17
- unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHeader *pblock, const Consensus::Params&);
18
- unsigned int CalculateNextWorkRequired(const CBlockIndex* pindexLast, int64_t nFirstBlockTime, const Consensus::Params&);
17
+ unsigned int GetNextTargetRequired(const CBlockIndex* pindexLast, bool fProofOfStake, const Consensus::Params& params);
19
18
 
20
19
  /** Check whether a block hash satisfies the proof-of-work requirement specified by nBits */
21
20
  bool CheckProofOfWork(uint256 hash, unsigned int nBits, const Consensus::Params&);
src/primitives/block.cpp CHANGED
@@ -10,19 +10,21 @@
10
10
 
11
11
  uint256 CBlockHeader::GetHash() const
12
12
  {
13
- return SerializeHash(*this);
13
+ CBlockHeader tmp(*this);
14
+ tmp.nFlags = 0;
15
+ return SerializeHash(tmp);
14
16
  }
15
17
 
16
18
  std::string CBlock::ToString() const
17
19
  {
18
20
  std::stringstream s;
19
- s << strprintf("CBlock(hash=%s, ver=0x%08x, hashPrevBlock=%s, hashMerkleRoot=%s, nTime=%u, nBits=%08x, nNonce=%u, vtx=%u)\n",
21
+ s << strprintf("CBlock(hash=%s, ver=0x%08x, hashPrevBlock=%s, hashMerkleRoot=%s, nTime=%u, nBits=%08x, nNonce=%u, nFlags=%08x, vtx=%u)\n",
20
22
  GetHash().ToString(),
21
23
  nVersion,
22
24
  hashPrevBlock.ToString(),
23
25
  hashMerkleRoot.ToString(),
24
26
  nTime, nBits, nNonce,
25
- vtx.size());
27
+ nFlags, vtx.size());
26
28
  for (const auto& tx : vtx) {
27
29
  s << " " << tx->ToString() << "\n";
28
30
  }
src/primitives/block.h CHANGED
@@ -28,21 +28,34 @@ public:
28
28
  uint32_t nBits;
29
29
  uint32_t nNonce;
30
30
 
31
+ // peercoin: A copy from CBlockIndex.nFlags from other clients. We need this information because we are using headers-first syncronization.
32
+ uint32_t nFlags;
33
+ // peercoin: Used in CheckProofOfStake().
34
+ static const int32_t NORMAL_SERIALIZE_SIZE=80;
35
+ static const int32_t CURRENT_VERSION=4;
36
+
31
37
  CBlockHeader()
32
38
  {
33
39
  SetNull();
34
40
  }
35
41
 
36
- SERIALIZE_METHODS(CBlockHeader, obj) { READWRITE(obj.nVersion, obj.hashPrevBlock, obj.hashMerkleRoot, obj.nTime, obj.nBits, obj.nNonce); }
42
+ SERIALIZE_METHODS(CBlockHeader, obj)
43
+ {
44
+ READWRITE(obj.nVersion, obj.hashPrevBlock, obj.hashMerkleRoot, obj.nTime, obj.nBits, obj.nNonce);
45
+ // peercoin: do not serialize nFlags when computing hash
46
+ if (!(s.GetType() & SER_GETHASH) && s.GetType() & SER_POSMARKER)
47
+ READWRITE(obj.nFlags);
48
+ }
37
49
 
38
50
  void SetNull()
39
51
  {
40
- nVersion = 0;
52
+ nVersion = CURRENT_VERSION;
41
53
  hashPrevBlock.SetNull();
42
54
  hashMerkleRoot.SetNull();
43
55
  nTime = 0;
44
56
  nBits = 0;
45
57
  nNonce = 0;
58
+ nFlags = 0;
46
59
  }
47
60
 
48
61
  bool IsNull() const
@@ -65,6 +78,9 @@ public:
65
78
  // network and disk
66
79
  std::vector<CTransactionRef> vtx;
67
80
 
81
+ // peercoin: block signature - signed by coin base txout[0]'s owner
82
+ std::vector<unsigned char> vchBlockSig;
83
+
68
84
  // memory only
69
85
  mutable bool fChecked;
70
86
 
@@ -83,6 +99,7 @@ public:
83
99
  {
84
100
  READWRITEAS(CBlockHeader, obj);
85
101
  READWRITE(obj.vtx);
102
+ READWRITE(obj.vchBlockSig);
86
103
  }
87
104
 
88
105
  void SetNull()
@@ -90,6 +107,7 @@ public:
90
107
  CBlockHeader::SetNull();
91
108
  vtx.clear();
92
109
  fChecked = false;
110
+ vchBlockSig.clear();
93
111
  }
94
112
 
95
113
  CBlockHeader GetBlockHeader() const
@@ -101,9 +119,37 @@ public:
101
119
  block.nTime = nTime;
102
120
  block.nBits = nBits;
103
121
  block.nNonce = nNonce;
122
+ block.nFlags = nFlags;
104
123
  return block;
105
124
  }
106
125
 
126
+ // peercoin: two types of block: proof-of-work or proof-of-stake
127
+ bool IsProofOfStake() const
128
+ {
129
+ return (vtx.size() > 1 && vtx[1]->IsCoinStake());
130
+ }
131
+
132
+ bool IsProofOfWork() const
133
+ {
134
+ return !IsProofOfStake();
135
+ }
136
+
137
+ std::pair<COutPoint, unsigned int> GetProofOfStake() const
138
+ {
139
+ return IsProofOfStake() ? std::make_pair(vtx[1]->vin[0].prevout, vtx[1]->nTime) : std::make_pair(COutPoint(), (unsigned int)0);
140
+ }
141
+
142
+ // peercoin: get max transaction timestamp
143
+ int64_t GetMaxTransactionTime() const
144
+ {
145
+ int64_t maxTransactionTime = 0;
146
+ for (const auto& tx : vtx)
147
+ maxTransactionTime = std::max(maxTransactionTime, (int64_t)tx->nTime);
148
+ return maxTransactionTime;
149
+ }
150
+
151
+ unsigned int GetStakeEntropyBit() const; // peercoin: entropy bit for stake modifier if chosen by modifier
152
+
107
153
  std::string ToString() const;
108
154
  };
109
155
 
src/primitives/transaction.cpp CHANGED
@@ -11,6 +11,7 @@
11
11
  #include <util/strencodings.h>
12
12
 
13
13
  #include <assert.h>
14
+ #include <timedata.h>
14
15
 
15
16
  std::string COutPoint::ToString() const
16
17
  {
@@ -54,11 +55,11 @@ CTxOut::CTxOut(const CAmount& nValueIn, CScript scriptPubKeyIn)
54
55
 
55
56
  std::string CTxOut::ToString() const
56
57
  {
57
- return strprintf("CTxOut(nValue=%d.%08d, scriptPubKey=%s)", nValue / COIN, nValue % COIN, HexStr(scriptPubKey).substr(0, 30));
58
+ return strprintf("CTxOut(nValue=%d.%06d, scriptPubKey=%s)", nValue / COIN, nValue % COIN, HexStr(scriptPubKey).substr(0, 30));
58
59
  }
59
60
 
60
- CMutableTransaction::CMutableTransaction() : nVersion(CTransaction::CURRENT_VERSION), nLockTime(0) {}
61
- CMutableTransaction::CMutableTransaction(const CTransaction& tx) : vin(tx.vin), vout(tx.vout), nVersion(tx.nVersion), nLockTime(tx.nLockTime) {}
61
+ CMutableTransaction::CMutableTransaction() : nVersion(CTransaction::CURRENT_VERSION), nTime(GetAdjustedTime()), nLockTime(0) {}
62
+ CMutableTransaction::CMutableTransaction(const CTransaction& tx) : vin(tx.vin), vout(tx.vout), nVersion(tx.nVersion), nTime(tx.nTime), nLockTime(tx.nLockTime) {}
62
63
 
63
64
  uint256 CMutableTransaction::GetHash() const
64
65
  {
@@ -78,8 +79,8 @@ uint256 CTransaction::ComputeWitnessHash() const
78
79
  return SerializeHash(*this, SER_GETHASH, 0);
79
80
  }
80
81
 
81
- CTransaction::CTransaction(const CMutableTransaction& tx) : vin(tx.vin), vout(tx.vout), nVersion(tx.nVersion), nLockTime(tx.nLockTime), hash{ComputeHash()}, m_witness_hash{ComputeWitnessHash()} {}
82
- CTransaction::CTransaction(CMutableTransaction&& tx) : vin(std::move(tx.vin)), vout(std::move(tx.vout)), nVersion(tx.nVersion), nLockTime(tx.nLockTime), hash{ComputeHash()}, m_witness_hash{ComputeWitnessHash()} {}
82
+ CTransaction::CTransaction(const CMutableTransaction& tx) : vin(tx.vin), vout(tx.vout), nVersion(tx.nVersion), nTime(tx.nTime), nLockTime(tx.nLockTime), hash{ComputeHash()}, m_witness_hash{ComputeWitnessHash()} {}
83
+ CTransaction::CTransaction(CMutableTransaction&& tx) : vin(std::move(tx.vin)), vout(std::move(tx.vout)), nVersion(tx.nVersion), nTime(tx.nTime), nLockTime(tx.nLockTime), hash{ComputeHash()}, m_witness_hash{ComputeWitnessHash()} {}
83
84
 
84
85
  CAmount CTransaction::GetValueOut() const
85
86
  {
@@ -101,8 +102,10 @@ unsigned int CTransaction::GetTotalSize() const
101
102
  std::string CTransaction::ToString() const
102
103
  {
103
104
  std::string str;
104
- str += strprintf("CTransaction(hash=%s, ver=%d, vin.size=%u, vout.size=%u, nLockTime=%u)\n",
105
+ str += IsCoinBase()? "Coinbase" : (IsCoinStake()? "Coinstake" : "CTransaction");
106
+ str += strprintf("(hash=%s, nTime=%d, ver=%d, vin.size=%u, vout.size=%u, nLockTime=%u)\n",
105
107
  GetHash().ToString().substr(0,10),
108
+ nTime,
106
109
  nVersion,
107
110
  vin.size(),
108
111
  vout.size(),
src/primitives/transaction.h CHANGED
@@ -12,6 +12,7 @@
12
12
  #include <serialize.h>
13
13
  #include <uint256.h>
14
14
 
15
+ #include <version.h>
15
16
  #include <tuple>
16
17
 
17
18
  /**
@@ -171,6 +172,17 @@ public:
171
172
  return (nValue == -1);
172
173
  }
173
174
 
175
+ void SetEmpty()
176
+ {
177
+ nValue = 0;
178
+ scriptPubKey.clear();
179
+ }
180
+
181
+ bool IsEmpty() const
182
+ {
183
+ return (nValue == 0 && scriptPubKey.empty());
184
+ }
185
+
174
186
  friend bool operator==(const CTxOut& a, const CTxOut& b)
175
187
  {
176
188
  return (a.nValue == b.nValue &&
@@ -209,6 +221,11 @@ inline void UnserializeTransaction(TxType& tx, Stream& s) {
209
221
  const bool fAllowWitness = !(s.GetVersion() & SERIALIZE_TRANSACTION_NO_WITNESS);
210
222
 
211
223
  s >> tx.nVersion;
224
+ if (tx.nVersion < 3)
225
+ s >> tx.nTime;
226
+ else
227
+ tx.nTime = 0;
228
+
212
229
  unsigned char flags = 0;
213
230
  tx.vin.clear();
214
231
  tx.vout.clear();
@@ -248,6 +265,8 @@ inline void SerializeTransaction(const TxType& tx, Stream& s) {
248
265
  const bool fAllowWitness = !(s.GetVersion() & SERIALIZE_TRANSACTION_NO_WITNESS);
249
266
 
250
267
  s << tx.nVersion;
268
+ if (tx.nVersion<3)
269
+ s << tx.nTime;
251
270
  unsigned char flags = 0;
252
271
  // Consistency check
253
272
  if (fAllowWitness) {
@@ -272,7 +291,6 @@ inline void SerializeTransaction(const TxType& tx, Stream& s) {
272
291
  s << tx.nLockTime;
273
292
  }
274
293
 
275
-
276
294
  /** The basic transaction that is broadcasted on the network and contained in
277
295
  * blocks. A transaction can contain multiple inputs and outputs.
278
296
  */
@@ -280,7 +298,7 @@ class CTransaction
280
298
  {
281
299
  public:
282
300
  // Default transaction version.
283
- static const int32_t CURRENT_VERSION=2;
301
+ static const int32_t CURRENT_VERSION=3;
284
302
 
285
303
  // The local variables are made const to prevent unintended modification
286
304
  // without updating the cached hash value. However, CTransaction is not
@@ -290,6 +308,7 @@ public:
290
308
  const std::vector<CTxIn> vin;
291
309
  const std::vector<CTxOut> vout;
292
310
  const int32_t nVersion;
311
+ const uint32_t nTime;
293
312
  const uint32_t nLockTime;
294
313
 
295
314
  private:
@@ -334,7 +353,13 @@ public:
334
353
 
335
354
  bool IsCoinBase() const
336
355
  {
337
- return (vin.size() == 1 && vin[0].prevout.IsNull());
356
+ return (vin.size() == 1 && vin[0].prevout.IsNull() && vout.size() >= 1);
357
+ }
358
+
359
+ bool IsCoinStake() const
360
+ {
361
+ // peercoin: the coin stake transaction is marked with the first output empty
362
+ return (vin.size() > 0 && (!vin[0].prevout.IsNull()) && vout.size() >= 2 && vout[0].IsEmpty());
338
363
  }
339
364
 
340
365
  friend bool operator==(const CTransaction& a, const CTransaction& b)
@@ -366,6 +391,7 @@ struct CMutableTransaction
366
391
  std::vector<CTxIn> vin;
367
392
  std::vector<CTxOut> vout;
368
393
  int32_t nVersion;
394
+ uint32_t nTime;
369
395
  uint32_t nLockTime;
370
396
 
371
397
  CMutableTransaction();
src/protocol.cpp CHANGED
@@ -181,6 +181,7 @@ const std::vector<std::string> &getAllNetMessageTypes()
181
181
  return allNetMessageTypesVec;
182
182
  }
183
183
 
184
+ const unsigned int POW_HEADER_COOLING = 70;
184
185
  /**
185
186
  * Convert a service flag (NODE_*) to a human readable string.
186
187
  * It supports unknown service flags which will be returned as "UNKNOWN[...]".
src/protocol.h CHANGED
@@ -273,7 +273,7 @@ enum ServiceFlags : uint64_t {
273
273
  // Nothing
274
274
  NODE_NONE = 0,
275
275
  // NODE_NETWORK means that the node is capable of serving the complete block chain. It is currently
276
- // set by all Bitcoin Core non pruned nodes, and is unset by SPV clients or other light clients.
276
+ // set by all Bitcoin Core nodes, and is unset by SPV clients or other light clients.
277
277
  NODE_NETWORK = (1 << 0),
278
278
  // NODE_BLOOM means the node is capable and willing to handle bloom-filtered connections.
279
279
  // Bitcoin Core nodes used to support this by default, without advertising this bit,
@@ -511,4 +511,7 @@ public:
511
511
  /** Convert a TX/WITNESS_TX/WTX CInv to a GenTxid. */
512
512
  GenTxid ToGenTxid(const CInv& inv);
513
513
 
514
+ /** peercoin: How much temperature a PoW header will remove */
515
+ extern const unsigned int POW_HEADER_COOLING;
516
+
514
517
  #endif // BITCOIN_PROTOCOL_H
src/psbt.h CHANGED
@@ -7,7 +7,6 @@
7
7
 
8
8
  #include <attributes.h>
9
9
  #include <node/transaction.h>
10
- #include <policy/feerate.h>
11
10
  #include <primitives/transaction.h>
12
11
  #include <pubkey.h>
13
12
  #include <script/keyorigin.h>
src/rest.cpp CHANGED
@@ -33,7 +33,6 @@
33
33
  #include <univalue.h>
34
34
 
35
35
  using node::GetTransaction;
36
- using node::IsBlockPruned;
37
36
  using node::NodeContext;
38
37
  using node::ReadBlockFromDisk;
39
38
 
@@ -296,8 +295,6 @@ static bool rest_block(const std::any& context,
296
295
  return RESTERR(req, HTTP_NOT_FOUND, hashStr + " not found");
297
296
  }
298
297
 
299
- if (IsBlockPruned(pblockindex))
300
- return RESTERR(req, HTTP_NOT_FOUND, hashStr + " not available (pruned data)");
301
298
 
302
299
  if (!ReadBlockFromDisk(block, pblockindex, Params().GetConsensus()))
303
300
  return RESTERR(req, HTTP_NOT_FOUND, hashStr + " not found");
src/script/interpreter.cpp CHANGED
@@ -1348,6 +1348,10 @@ public:
1348
1348
  void Serialize(S &s) const {
1349
1349
  // Serialize nVersion
1350
1350
  ::Serialize(s, txTo.nVersion);
1351
+ if (txTo.nVersion < 3) {
1352
+ // Serialize nTime
1353
+ ::Serialize(s, txTo.nTime);
1354
+ }
1351
1355
  // Serialize vin
1352
1356
  unsigned int nInputs = fAnyoneCanPay ? 1 : txTo.vin.size();
1353
1357
  ::WriteCompactSize(s, nInputs);
@@ -1620,6 +1624,10 @@ uint256 SignatureHash(const CScript& scriptCode, const T& txTo, unsigned int nIn
1620
1624
  CHashWriter ss(SER_GETHASH, 0);
1621
1625
  // Version
1622
1626
  ss << txTo.nVersion;
1627
+ if (txTo.nVersion < 3) {
1628
+ // nTime
1629
+ ss << txTo.nTime;
1630
+ }
1623
1631
  // Input prevouts/nSequence (none/all, depending on flags)
1624
1632
  ss << hashPrevouts;
1625
1633
  ss << hashSequence;
src/script/script.cpp CHANGED
@@ -7,6 +7,7 @@
7
7
 
8
8
  #include <util/strencodings.h>
9
9
 
10
+ #include <key.h>
10
11
  #include <string>
11
12
 
12
13
  std::string GetOpName(opcodetype opcode)
@@ -280,6 +281,19 @@ bool CScript::HasValidOps() const
280
281
  return true;
281
282
  }
282
283
 
284
+ void CScript::SetMultisig(int nRequired, const std::vector<CPubKey>& keys)
285
+ {
286
+ this->clear();
287
+
288
+ *this << EncodeOP_N(nRequired);
289
+ for (const auto& pubkey : keys)
290
+ {
291
+ std::vector<unsigned char> vchPubKey(pubkey.begin(), pubkey.end());
292
+ *this << vchPubKey;
293
+ }
294
+ *this << EncodeOP_N(keys.size()) << OP_CHECKMULTISIG;
295
+ }
296
+
283
297
  bool GetScriptOp(CScriptBase::const_iterator& pc, CScriptBase::const_iterator end, opcodetype& opcodeRet, std::vector<unsigned char>* pvchRet)
284
298
  {
285
299
  opcodeRet = OP_INVALIDOPCODE;
src/script/script.h CHANGED
@@ -20,6 +20,8 @@
20
20
  #include <string>
21
21
  #include <vector>
22
22
 
23
+ class CPubKey;
24
+
23
25
  // Maximum number of bytes pushable to the stack
24
26
  static const unsigned int MAX_SCRIPT_ELEMENT_SIZE = 520;
25
27
 
@@ -223,7 +225,7 @@ class CScriptNum
223
225
  * The semantics are subtle, though: operands must be in the range [-2^31 +1...2^31 -1],
224
226
  * but results may overflow (and are valid as long as they are not used in a subsequent
225
227
  * numeric operation). CScriptNum enforces those semantics by storing results as
226
- * an int64 and allowing out-of-range values to be returned as a vector of bytes but
228
+ * an int64_t and allowing out-of-range values to be returned as a vector of bytes but
227
229
  * throwing an exception if arithmetic is done or the result is interpreted as an integer.
228
230
  */
229
231
  public:
@@ -552,6 +554,8 @@ public:
552
554
  CScriptBase::clear();
553
555
  shrink_to_fit();
554
556
  }
557
+
558
+ void SetMultisig(int nRequired, const std::vector<CPubKey>& keys);
555
559
  };
556
560
 
557
561
  struct CScriptWitness
src/script/sign.cpp CHANGED
@@ -622,6 +622,10 @@ bool SignTransaction(CMutableTransaction& mtx, const SigningProvider* keystore,
622
622
  {
623
623
  bool fHashSingle = ((nHashType & ~SIGHASH_ANYONECANPAY) == SIGHASH_SINGLE);
624
624
 
625
+ // we don't need nTime anymore
626
+ if (mtx.nVersion >= 3)
627
+ mtx.nTime = 0;
628
+
625
629
  // Use CTransaction for the constant parts of the
626
630
  // transaction to avoid rehashing.
627
631
  const CTransaction txConst(mtx);
src/script/standard.h CHANGED
@@ -32,10 +32,10 @@ public:
32
32
  };
33
33
 
34
34
  /**
35
- * Default setting for nMaxDatacarrierBytes. 80 bytes of data, +1 for OP_RETURN,
35
+ * Default setting for nMaxDatacarrierBytes. 256 bytes of data, +1 for OP_RETURN,
36
36
  * +2 for the pushdata opcodes.
37
37
  */
38
- static const unsigned int MAX_OP_RETURN_RELAY = 83;
38
+ static const unsigned int MAX_OP_RETURN_RELAY = 259;
39
39
 
40
40
  /**
41
41
  * A data carrying output is an unspendable output containing data. The script
src/serialize.h CHANGED
@@ -131,6 +131,8 @@ enum
131
131
  SER_NETWORK = (1 << 0),
132
132
  SER_DISK = (1 << 1),
133
133
  SER_GETHASH = (1 << 2),
134
+
135
+ SER_POSMARKER = (1 << 18), // peercoin: for sending block headers with PoS marker, to allow headers-first syncronization
134
136
  };
135
137
 
136
138
  //! Convert the reference base type to X, without changing constness or reference type.
@@ -984,9 +986,10 @@ class CSizeComputer
984
986
  protected:
985
987
  size_t nSize;
986
988
 
989
+ const int nType;
987
990
  const int nVersion;
988
991
  public:
989
- explicit CSizeComputer(int nVersionIn) : nSize(0), nVersion(nVersionIn) {}
992
+ explicit CSizeComputer(int nTypeIn, int nVersionIn) : nSize(0), nType(nTypeIn), nVersion(nVersionIn) {}
990
993
 
991
994
  void write(Span<const std::byte> src)
992
995
  {
@@ -1010,6 +1013,7 @@ public:
1010
1013
  return nSize;
1011
1014
  }
1012
1015
 
1016
+ int GetType() const { return nType; }
1013
1017
  int GetVersion() const { return nVersion; }
1014
1018
  };
1015
1019
 
@@ -1083,15 +1087,15 @@ inline void WriteCompactSize(CSizeComputer &s, uint64_t nSize)
1083
1087
  }
1084
1088
 
1085
1089
  template <typename T>
1086
- size_t GetSerializeSize(const T& t, int nVersion = 0)
1090
+ size_t GetSerializeSize(const T& t, int nType, int nVersion = 0)
1087
1091
  {
1088
- return (CSizeComputer(nVersion) << t).size();
1092
+ return (CSizeComputer(nType, nVersion) << t).size();
1089
1093
  }
1090
1094
 
1091
1095
  template <typename... T>
1092
1096
  size_t GetSerializeSizeMany(int nVersion, const T&... t)
1093
1097
  {
1094
- CSizeComputer sc(nVersion);
1098
+ CSizeComputer sc(0, nVersion);
1095
1099
  SerializeMany(sc, t...);
1096
1100
  return sc.size();
1097
1101
  }
src/timedatadummy.cpp ADDED
@@ -0,0 +1,7 @@
1
+ #include <stdint.h>
2
+
3
+ // needed when linking transaction.cpp, since we are not going to pull real GetAdjustedTime from timedata.cpp
4
+ int64_t GetAdjustedTime()
5
+ {
6
+ return 0;
7
+ }
src/txdb.cpp CHANGED
@@ -322,7 +322,16 @@ bool CBlockTreeDB::LoadBlockIndexGuts(const Consensus::Params& consensusParams,
322
322
  pindexNew->nStatus = diskindex.nStatus;
323
323
  pindexNew->nTx = diskindex.nTx;
324
324
 
325
- if (!CheckProofOfWork(pindexNew->GetBlockHash(), pindexNew->nBits, consensusParams)) {
325
+ // peercoin related block index fields
326
+ pindexNew->nMint = diskindex.nMint;
327
+ pindexNew->nMoneySupply = diskindex.nMoneySupply;
328
+ pindexNew->nFlags = diskindex.nFlags;
329
+ pindexNew->nStakeModifier = diskindex.nStakeModifier;
330
+ pindexNew->prevoutStake = diskindex.prevoutStake;
331
+ pindexNew->nStakeTime = diskindex.nStakeTime;
332
+ pindexNew->hashProofOfStake = diskindex.hashProofOfStake;
333
+
334
+ if (pindexNew->IsProofOfWork() && !CheckProofOfWork(pindexNew->GetBlockHash(), pindexNew->nBits, consensusParams)) {
326
335
  return error("%s: CheckProofOfWork failed: %s", __func__, pindexNew->ToString());
327
336
  }
328
337
 
@@ -353,6 +362,12 @@ public:
353
362
  //! at which height this transaction was included in the active block chain
354
363
  int nHeight;
355
364
 
365
+ // peercoin: whether transaction is a coinstake
366
+ bool fCoinStake;
367
+
368
+ // peercoin: transaction timestamp
369
+ unsigned int nTime;
370
+
356
371
  //! empty constructor
357
372
  CCoins() : fCoinBase(false), vout(0), nHeight(0) { }
358
373
 
@@ -435,7 +450,7 @@ bool CCoinsViewDB::Upgrade() {
435
450
  COutPoint outpoint(key.second, 0);
436
451
  for (size_t i = 0; i < old_coins.vout.size(); ++i) {
437
452
  if (!old_coins.vout[i].IsNull() && !old_coins.vout[i].scriptPubKey.IsUnspendable()) {
438
- Coin newcoin(std::move(old_coins.vout[i]), old_coins.nHeight, old_coins.fCoinBase);
453
+ Coin newcoin(std::move(old_coins.vout[i]), old_coins.nHeight, old_coins.fCoinBase, old_coins.fCoinStake, old_coins.nTime);
439
454
  outpoint.n = i;
440
455
  CoinEntry entry(&outpoint);
441
456
  batch.Write(entry, newcoin);
src/txmempool.cpp CHANGED
@@ -10,15 +10,17 @@
10
10
  #include <consensus/consensus.h>
11
11
  #include <consensus/tx_verify.h>
12
12
  #include <consensus/validation.h>
13
- #include <policy/fees.h>
13
+ #include <kernel.h>
14
14
  #include <policy/policy.h>
15
15
  #include <policy/settings.h>
16
16
  #include <reverse_iterator.h>
17
+ #include <timedata.h>
17
18
  #include <util/moneystr.h>
18
19
  #include <util/system.h>
19
20
  #include <util/time.h>
20
21
  #include <validationinterface.h>
21
22
 
23
+ #include <chainparams.h>
22
24
  #include <cmath>
23
25
  #include <optional>
24
26
 
@@ -461,8 +463,8 @@ void CTxMemPoolEntry::UpdateAncestorState(int64_t modifySize, CAmount modifyFee,
461
463
  assert(int(nSigOpCostWithAncestors) >= 0);
462
464
  }
463
465
 
464
- CTxMemPool::CTxMemPool(CBlockPolicyEstimator* estimator, int check_ratio)
465
- : m_check_ratio(check_ratio), minerPolicyEstimator(estimator)
466
+ CTxMemPool::CTxMemPool(int check_ratio)
467
+ : m_check_ratio(check_ratio)
466
468
  {
467
469
  _clear(); //lock free clear
468
470
  }
@@ -483,7 +485,7 @@ void CTxMemPool::AddTransactionsUpdated(unsigned int n)
483
485
  nTransactionsUpdated += n;
484
486
  }
485
487
 
486
- void CTxMemPool::addUnchecked(const CTxMemPoolEntry &entry, setEntries &setAncestors, bool validFeeEstimate)
488
+ void CTxMemPool::addUnchecked(const CTxMemPoolEntry &entry, setEntries &setAncestors)
487
489
  {
488
490
  // Add to memory pool without checking anything.
489
491
  // Used by AcceptToMemoryPool(), which DOES do
@@ -526,10 +528,6 @@ void CTxMemPool::addUnchecked(const CTxMemPoolEntry &entry, setEntries &setAnces
526
528
 
527
529
  nTransactionsUpdated++;
528
530
  totalTxSize += entry.GetTxSize();
529
- m_total_fee += entry.GetFee();
530
- if (minerPolicyEstimator) {
531
- minerPolicyEstimator->processTransaction(entry, validFeeEstimate);
532
- }
533
531
 
534
532
  vTxHashes.emplace_back(tx.GetWitnessHash(), newit);
535
533
  newit->vTxHashesIdx = vTxHashes.size() - 1;
@@ -549,12 +547,9 @@ void CTxMemPool::removeUnchecked(txiter it, MemPoolRemovalReason reason)
549
547
  GetMainSignals().TransactionRemovedFromMempool(it->GetSharedTx(), reason, mempool_sequence);
550
548
  }
551
549
 
552
- const uint256 hash = it->GetTx().GetHash();
553
550
  for (const CTxIn& txin : it->GetTx().vin)
554
551
  mapNextTx.erase(txin.prevout);
555
552
 
556
- RemoveUnbroadcastTx(hash, true /* add logging because unchecked */ );
557
-
558
553
  if (vTxHashes.size() > 1) {
559
554
  vTxHashes[it->vTxHashesIdx] = std::move(vTxHashes.back());
560
555
  vTxHashes[it->vTxHashesIdx].second->vTxHashesIdx = it->vTxHashesIdx;
@@ -570,7 +565,6 @@ void CTxMemPool::removeUnchecked(txiter it, MemPoolRemovalReason reason)
570
565
  cachedInnerUsage -= memusage::DynamicUsage(it->GetMemPoolParentsConst()) + memusage::DynamicUsage(it->GetMemPoolChildrenConst());
571
566
  mapTx.erase(it);
572
567
  nTransactionsUpdated++;
573
- if (minerPolicyEstimator) {minerPolicyEstimator->removeTx(hash, false);}
574
568
  }
575
569
 
576
570
  // Calculates descendants of entry that are not already in setDescendants, and adds to
@@ -685,8 +679,6 @@ void CTxMemPool::removeForBlock(const std::vector<CTransactionRef>& vtx, unsigne
685
679
  if (i != mapTx.end())
686
680
  entries.push_back(&*i);
687
681
  }
688
- // Before the txs in the new block have been removed from the mempool, update policy estimates
689
- if (minerPolicyEstimator) {minerPolicyEstimator->processBlock(nBlockHeight, entries);}
690
682
  for (const auto& tx : vtx)
691
683
  {
692
684
  txiter it = mapTx.find(tx->GetHash());
@@ -698,8 +690,6 @@ void CTxMemPool::removeForBlock(const std::vector<CTransactionRef>& vtx, unsigne
698
690
  removeConflicts(*tx);
699
691
  ClearPrioritisation(tx->GetHash());
700
692
  }
701
- lastRollingFeeUpdate = GetTime();
702
- blockSinceLastRollingFeeBump = true;
703
693
  }
704
694
 
705
695
  void CTxMemPool::_clear()
@@ -709,9 +699,6 @@ void CTxMemPool::_clear()
709
699
  totalTxSize = 0;
710
700
  m_total_fee = 0;
711
701
  cachedInnerUsage = 0;
712
- lastRollingFeeUpdate = GetTime();
713
- blockSinceLastRollingFeeBump = false;
714
- rollingMinimumFeeRate = 0;
715
702
  ++nTransactionsUpdated;
716
703
  }
717
704
 
@@ -812,9 +799,9 @@ void CTxMemPool::check(const CCoinsViewCache& active_coins_tip, int64_t spendhei
812
799
  TxValidationState dummy_state; // Not used. CheckTxInputs() should always pass
813
800
  CAmount txfee = 0;
814
801
  assert(!tx.IsCoinBase());
815
- assert(Consensus::CheckTxInputs(tx, dummy_state, mempoolDuplicate, spendheight, txfee));
802
+ assert(Consensus::CheckTxInputs(tx, dummy_state, mempoolDuplicate, spendheight, txfee, Params().GetConsensus(), tx.nTime ? tx.nTime : GetAdjustedTime()));
816
803
  for (const auto& input: tx.vin) mempoolDuplicate.SpendCoin(input.prevout);
817
- AddCoins(mempoolDuplicate, tx, std::numeric_limits<int>::max());
804
+ AddCoins(mempoolDuplicate, tx, std::numeric_limits<int>::max(), false, true);
818
805
  }
819
806
  for (auto it = mapNextTx.cbegin(); it != mapNextTx.cend(); it++) {
820
807
  uint256 hash = it->second->GetHash();
@@ -1016,7 +1003,7 @@ bool CCoinsViewMemPool::GetCoin(const COutPoint &outpoint, Coin &coin) const {
1016
1003
  CTransactionRef ptx = mempool.get(outpoint.hash);
1017
1004
  if (ptx) {
1018
1005
  if (outpoint.n < ptx->vout.size()) {
1019
- coin = Coin(ptx->vout[outpoint.n], MEMPOOL_HEIGHT, false);
1006
+ coin = Coin(ptx->vout[outpoint.n], MEMPOOL_HEIGHT, false, ptx->IsCoinStake(), ptx->nTime);
1020
1007
  return true;
1021
1008
  } else {
1022
1009
  return false;
@@ -1028,7 +1015,7 @@ bool CCoinsViewMemPool::GetCoin(const COutPoint &outpoint, Coin &coin) const {
1028
1015
  void CCoinsViewMemPool::PackageAddTransaction(const CTransactionRef& tx)
1029
1016
  {
1030
1017
  for (unsigned int n = 0; n < tx->vout.size(); ++n) {
1031
- m_temp_added.emplace(COutPoint(tx->GetHash(), n), Coin(tx->vout[n], MEMPOOL_HEIGHT, false));
1018
+ m_temp_added.emplace(COutPoint(tx->GetHash(), n), Coin(tx->vout[n], MEMPOOL_HEIGHT, false, tx->IsCoinStake(), tx->nTime));
1032
1019
  }
1033
1020
  }
1034
1021
 
@@ -1072,13 +1059,13 @@ int CTxMemPool::Expire(std::chrono::seconds time)
1072
1059
  return stage.size();
1073
1060
  }
1074
1061
 
1075
- void CTxMemPool::addUnchecked(const CTxMemPoolEntry &entry, bool validFeeEstimate)
1062
+ void CTxMemPool::addUnchecked(const CTxMemPoolEntry &entry)
1076
1063
  {
1077
1064
  setEntries setAncestors;
1078
1065
  uint64_t nNoLimit = std::numeric_limits<uint64_t>::max();
1079
1066
  std::string dummy;
1080
1067
  CalculateMemPoolAncestors(entry, setAncestors, nNoLimit, nNoLimit, nNoLimit, nNoLimit, dummy);
1081
- return addUnchecked(entry, setAncestors, validFeeEstimate);
1068
+ return addUnchecked(entry, setAncestors);
1082
1069
  }
1083
1070
 
1084
1071
  void CTxMemPool::UpdateChild(txiter entry, txiter child, bool add)
@@ -1103,55 +1090,13 @@ void CTxMemPool::UpdateParent(txiter entry, txiter parent, bool add)
1103
1090
  }
1104
1091
  }
1105
1092
 
1106
- CFeeRate CTxMemPool::GetMinFee(size_t sizelimit) const {
1107
- LOCK(cs);
1108
- if (!blockSinceLastRollingFeeBump || rollingMinimumFeeRate == 0)
1109
- return CFeeRate(llround(rollingMinimumFeeRate));
1110
-
1111
- int64_t time = GetTime();
1112
- if (time > lastRollingFeeUpdate + 10) {
1113
- double halflife = ROLLING_FEE_HALFLIFE;
1114
- if (DynamicMemoryUsage() < sizelimit / 4)
1115
- halflife /= 4;
1116
- else if (DynamicMemoryUsage() < sizelimit / 2)
1117
- halflife /= 2;
1118
-
1119
- rollingMinimumFeeRate = rollingMinimumFeeRate / pow(2.0, (time - lastRollingFeeUpdate) / halflife);
1120
- lastRollingFeeUpdate = time;
1121
-
1122
- if (rollingMinimumFeeRate < (double)incrementalRelayFee.GetFeePerK() / 2) {
1123
- rollingMinimumFeeRate = 0;
1124
- return CFeeRate(0);
1125
- }
1126
- }
1127
- return std::max(CFeeRate(llround(rollingMinimumFeeRate)), incrementalRelayFee);
1128
- }
1129
-
1130
- void CTxMemPool::trackPackageRemoved(const CFeeRate& rate) {
1131
- AssertLockHeld(cs);
1132
- if (rate.GetFeePerK() > rollingMinimumFeeRate) {
1133
- rollingMinimumFeeRate = rate.GetFeePerK();
1134
- blockSinceLastRollingFeeBump = false;
1135
- }
1136
- }
1137
-
1138
1093
  void CTxMemPool::TrimToSize(size_t sizelimit, std::vector<COutPoint>* pvNoSpendsRemaining) {
1139
1094
  AssertLockHeld(cs);
1140
1095
 
1141
1096
  unsigned nTxnRemoved = 0;
1142
- CFeeRate maxFeeRateRemoved(0);
1143
1097
  while (!mapTx.empty() && DynamicMemoryUsage() > sizelimit) {
1144
1098
  indexed_transaction_set::index<descendant_score>::type::iterator it = mapTx.get<descendant_score>().begin();
1145
1099
 
1146
- // We set the new mempool min fee to the feerate of the removed set, plus the
1147
- // "minimum reasonable fee rate" (ie some value under which we consider txn
1148
- // to have 0 fee). This way, we don't allow txn to enter mempool with feerate
1149
- // equal to txn which were removed with no block in between.
1150
- CFeeRate removed(it->GetModFeesWithDescendants(), it->GetSizeWithDescendants());
1151
- removed += incrementalRelayFee;
1152
- trackPackageRemoved(removed);
1153
- maxFeeRateRemoved = std::max(maxFeeRateRemoved, removed);
1154
-
1155
1100
  setEntries stage;
1156
1101
  CalculateDescendants(mapTx.project<0>(it), stage);
1157
1102
  nTxnRemoved += stage.size();
@@ -1172,10 +1117,6 @@ void CTxMemPool::TrimToSize(size_t sizelimit, std::vector<COutPoint>* pvNoSpends
1172
1117
  }
1173
1118
  }
1174
1119
  }
1175
-
1176
- if (maxFeeRateRemoved > CFeeRate(0)) {
1177
- LogPrint(BCLog::MEMPOOL, "Removed %u txn, rolling minimum fee bumped to %s\n", nTxnRemoved, maxFeeRateRemoved.ToString());
1178
- }
1179
1120
  }
1180
1121
 
1181
1122
  uint64_t CTxMemPool::CalculateDescendantMaximum(txiter entry) const {
src/txmempool.h CHANGED
@@ -17,7 +17,6 @@
17
17
  #include <coins.h>
18
18
  #include <consensus/amount.h>
19
19
  #include <indirectmap.h>
20
- #include <policy/feerate.h>
21
20
  #include <policy/packages.h>
22
21
  #include <primitives/transaction.h>
23
22
  #include <random.h>
@@ -318,8 +317,6 @@ struct entry_time {};
318
317
  struct ancestor_score {};
319
318
  struct index_by_wtxid {};
320
319
 
321
- class CBlockPolicyEstimator;
322
-
323
320
  /**
324
321
  * Information about a mempool transaction.
325
322
  */
@@ -361,9 +358,6 @@ enum class MemPoolRemovalReason {
361
358
  * local node), but not all transactions seen are added to the pool. For
362
359
  * example, the following new transactions will not be added to the mempool:
363
360
  * - a transaction which doesn't meet the minimum fee requirements.
364
- * - a new transaction that double-spends an input of a transaction already in
365
- * the pool where the new transaction does not meet the Replace-By-Fee
366
- * requirements as defined in BIP 125.
367
361
  * - a non-standard transaction.
368
362
  *
369
363
  * CTxMemPool::mapTx, and CTxMemPoolEntry bookkeeping:
@@ -431,24 +425,17 @@ class CTxMemPool
431
425
  protected:
432
426
  const int m_check_ratio; //!< Value n means that 1 times in n we check.
433
427
  std::atomic<unsigned int> nTransactionsUpdated{0}; //!< Used by getblocktemplate to trigger CreateNewBlock() invocation
434
- CBlockPolicyEstimator* const minerPolicyEstimator;
435
428
 
436
429
  uint64_t totalTxSize GUARDED_BY(cs); //!< sum of all mempool tx's virtual sizes. Differs from serialized tx size since witness data is discounted. Defined in BIP 141.
437
430
  CAmount m_total_fee GUARDED_BY(cs); //!< sum of all mempool tx's fees (NOT modified fee)
438
431
  uint64_t cachedInnerUsage GUARDED_BY(cs); //!< sum of dynamic memory usage of all the map elements (NOT the maps themselves)
439
432
 
440
- mutable int64_t lastRollingFeeUpdate GUARDED_BY(cs);
441
- mutable bool blockSinceLastRollingFeeBump GUARDED_BY(cs);
442
- mutable double rollingMinimumFeeRate GUARDED_BY(cs); //!< minimum fee to get into the pool, decreases exponentially
443
433
  mutable Epoch m_epoch GUARDED_BY(cs);
444
-
445
434
  // In-memory counter for external mempool tracking purposes.
446
435
  // This number is incremented once every time a transaction
447
436
  // is added or removed from the mempool for any reason.
448
437
  mutable uint64_t m_sequence_number GUARDED_BY(cs){1};
449
438
 
450
- void trackPackageRemoved(const CFeeRate& rate) EXCLUSIVE_LOCKS_REQUIRED(cs);
451
-
452
439
  bool m_is_loaded GUARDED_BY(cs){false};
453
440
 
454
441
  public:
@@ -568,7 +555,7 @@ public:
568
555
  * @param[in] estimator is used to estimate appropriate transaction fees.
569
556
  * @param[in] check_ratio is the ratio used to determine how often sanity checks will run.
570
557
  */
571
- explicit CTxMemPool(CBlockPolicyEstimator* estimator = nullptr, int check_ratio = 0);
558
+ explicit CTxMemPool(int check_ratio = 0);
572
559
 
573
560
  /**
574
561
  * If sanity-checking is turned on, check makes sure the pool is
@@ -585,8 +572,8 @@ public:
585
572
  // Note that addUnchecked is ONLY called from ATMP outside of tests
586
573
  // and any other callers may break wallet's in-mempool tracking (due to
587
574
  // lack of CValidationInterface::TransactionAddedToMempool callbacks).
588
- void addUnchecked(const CTxMemPoolEntry& entry, bool validFeeEstimate = true) EXCLUSIVE_LOCKS_REQUIRED(cs, cs_main);
589
- void addUnchecked(const CTxMemPoolEntry& entry, setEntries& setAncestors, bool validFeeEstimate = true) EXCLUSIVE_LOCKS_REQUIRED(cs, cs_main);
575
+ void addUnchecked(const CTxMemPoolEntry& entry) EXCLUSIVE_LOCKS_REQUIRED(cs, cs_main);
576
+ void addUnchecked(const CTxMemPoolEntry& entry, setEntries& setAncestors) EXCLUSIVE_LOCKS_REQUIRED(cs, cs_main);
590
577
 
591
578
  void removeRecursive(const CTransaction& tx, MemPoolRemovalReason reason) EXCLUSIVE_LOCKS_REQUIRED(cs);
592
579
  /** After reorg, filter the entries that would no longer be valid in the next block, and update
@@ -695,14 +682,6 @@ public:
695
682
  * already in it. */
696
683
  void CalculateDescendants(txiter it, setEntries& setDescendants) const EXCLUSIVE_LOCKS_REQUIRED(cs);
697
684
 
698
- /** The minimum fee to get into the mempool, which may itself not be enough
699
- * for larger-sized transactions.
700
- * The incrementalRelayFee policy variable is used to bound the time it
701
- * takes the fee rate to go back down all the way to 0. When the feerate
702
- * would otherwise be half of this, it is set to 0 instead.
703
- */
704
- CFeeRate GetMinFee(size_t sizelimit) const;
705
-
706
685
  /** Remove transactions from the mempool until its dynamic size is <= sizelimit.
707
686
  * pvNoSpendsRemaining, if set, will be populated with the list of outpoints
708
687
  * which are not in mempool which no longer have any spends in this mempool.
src/uint256.h CHANGED
@@ -22,6 +22,11 @@ protected:
22
22
  static constexpr int WIDTH = BITS / 8;
23
23
  uint8_t m_data[WIDTH];
24
24
  public:
25
+ const uint32_t *GetDataPtr() const
26
+ {
27
+ return (const uint32_t *)m_data;
28
+ }
29
+
25
30
  /* construct 0 value by default */
26
31
  constexpr base_blob() : m_data() {}
27
32
 
src/undo.h CHANGED
@@ -24,7 +24,8 @@ struct TxInUndoFormatter
24
24
  {
25
25
  template<typename Stream>
26
26
  void Ser(Stream &s, const Coin& txout) {
27
- ::Serialize(s, VARINT(txout.nHeight * uint32_t{2} + txout.fCoinBase ));
27
+ ::Serialize(s, VARINT(txout.nHeight * uint32_t{4} + txout.fCoinBase + (txout.fCoinStake ? 2u : 0u)));
28
+ ::Serialize(s, VARINT(txout.nTime));
28
29
  if (txout.nHeight > 0) {
29
30
  // Required to maintain compatibility with older undo format.
30
31
  ::Serialize(s, (unsigned char)0);
@@ -36,8 +37,10 @@ struct TxInUndoFormatter
36
37
  void Unser(Stream &s, Coin& txout) {
37
38
  uint32_t nCode = 0;
38
39
  ::Unserialize(s, VARINT(nCode));
39
- txout.nHeight = nCode >> 1;
40
+ txout.nHeight = nCode >> 2;
40
41
  txout.fCoinBase = nCode & 1;
42
+ txout.fCoinStake = nCode & 2;
43
+ ::Unserialize(s, VARINT(txout.nTime));
41
44
  if (txout.nHeight > 0) {
42
45
  // Old versions stored the version number for the last spend of
43
46
  // a transaction's outputs. Non-final spends were indicated with
src/util.h ADDED
@@ -0,0 +1,74 @@
1
+ /**********************************************************************
2
+ * Copyright (c) 2018 Pieter Wuille, Greg Maxwell, Gleb Naumenko *
3
+ * Distributed under the MIT software license, see the accompanying *
4
+ * file LICENSE or http://www.opensource.org/licenses/mit-license.php.*
5
+ **********************************************************************/
6
+
7
+ #ifndef _MINISKETCH_UTIL_H_
8
+ #define _MINISKETCH_UTIL_H_
9
+
10
+ #ifdef MINISKETCH_VERIFY
11
+ #include <stdio.h>
12
+ #endif
13
+
14
+ #if !defined(__GNUC_PREREQ)
15
+ # if defined(__GNUC__)&&defined(__GNUC_MINOR__)
16
+ # define __GNUC_PREREQ(_maj,_min) \
17
+ ((__GNUC__<<16)+__GNUC_MINOR__>=((_maj)<<16)+(_min))
18
+ # else
19
+ # define __GNUC_PREREQ(_maj,_min) 0
20
+ # endif
21
+ #endif
22
+
23
+ #if __GNUC_PREREQ(3, 0)
24
+ #define EXPECT(x,c) __builtin_expect((x),(c))
25
+ #else
26
+ #define EXPECT(x,c) (x)
27
+ #endif
28
+
29
+ /* Assertion macros */
30
+
31
+ /**
32
+ * Unconditional failure on condition failure.
33
+ * Primarily used in testing harnesses.
34
+ */
35
+ #define CHECK(cond) do { \
36
+ if (EXPECT(!(cond), 0)) { \
37
+ fprintf(stderr, "%s:%d: %s\n", __FILE__, __LINE__, "Check condition failed: " #cond); \
38
+ abort(); \
39
+ } \
40
+ } while(0)
41
+
42
+ /**
43
+ * Check macro that does nothing in normal non-verify builds but crashes in verify builds.
44
+ * This is used to test conditions at runtime that should always be true, but are either
45
+ * expensive to test or in locations where returning on failure would be messy.
46
+ */
47
+ #ifdef MINISKETCH_VERIFY
48
+ #define CHECK_SAFE(cond) CHECK(cond)
49
+ #else
50
+ #define CHECK_SAFE(cond)
51
+ #endif
52
+
53
+ /**
54
+ * Check a condition and return on failure in non-verify builds, crash in verify builds.
55
+ * Used for inexpensive conditions which believed to be always true in locations where
56
+ * a graceful exit is possible.
57
+ */
58
+ #ifdef MINISKETCH_VERIFY
59
+ #define CHECK_RETURN(cond, rvar) do { \
60
+ if (EXPECT(!(cond), 0)) { \
61
+ fprintf(stderr, "%s:%d: %s\n", __FILE__, __LINE__, "Check condition failed: " #cond); \
62
+ abort(); \
63
+ return rvar; /* Does nothing, but causes compile to warn on incorrect return types. */ \
64
+ } \
65
+ } while(0)
66
+ #else
67
+ #define CHECK_RETURN(cond, rvar) do { \
68
+ if (EXPECT(!(cond), 0)) { \
69
+ return rvar; \
70
+ } \
71
+ } while(0)
72
+ #endif
73
+
74
+ #endif
src/util/error.cpp CHANGED
@@ -29,8 +29,6 @@ bilingual_str TransactionErrorString(const TransactionError err)
29
29
  return Untranslated("PSBTs not compatible (different transactions)");
30
30
  case TransactionError::SIGHASH_MISMATCH:
31
31
  return Untranslated("Specified sighash value does not match value stored in PSBT");
32
- case TransactionError::MAX_FEE_EXCEEDED:
33
- return Untranslated("Fee exceeds maximum configured by user (e.g. -maxtxfee, maxfeerate)");
34
32
  case TransactionError::EXTERNAL_SIGNER_NOT_FOUND:
35
33
  return Untranslated("External signer not found");
36
34
  case TransactionError::EXTERNAL_SIGNER_FAILED:
src/util/error.h CHANGED
@@ -29,7 +29,6 @@ enum class TransactionError {
29
29
  INVALID_PSBT,
30
30
  PSBT_MISMATCH,
31
31
  SIGHASH_MISMATCH,
32
- MAX_FEE_EXCEEDED,
33
32
  EXTERNAL_SIGNER_NOT_FOUND,
34
33
  EXTERNAL_SIGNER_FAILED,
35
34
  };
src/util/message.cpp CHANGED
@@ -19,7 +19,7 @@
19
19
  * Text used to signify that a signed message follows and to prevent
20
20
  * inadvertently signing a transaction.
21
21
  */
22
- const std::string MESSAGE_MAGIC = "Bitcoin Signed Message:\n";
22
+ const std::string MESSAGE_MAGIC = "Peercoin Signed Message:\n";
23
23
 
24
24
  MessageVerificationResult MessageVerify(
25
25
  const std::string& address,
src/util/moneystr.cpp CHANGED
@@ -23,7 +23,7 @@ std::string FormatMoney(const CAmount n)
23
23
  quotient = -quotient;
24
24
  remainder = -remainder;
25
25
  }
26
- std::string str = strprintf("%d.%08d", quotient, remainder);
26
+ std::string str = strprintf("%d.%06d", quotient, remainder);
27
27
 
28
28
  // Right-trim excess zeros before the decimal point:
29
29
  int nTrim = 0;
src/util/strencodings.cpp CHANGED
@@ -426,13 +426,17 @@ bool ParseFixedPoint(const std::string &val, int decimals, int64_t *amount_out)
426
426
  if (ptr < end && val[ptr] == '.')
427
427
  {
428
428
  ++ptr;
429
+ int peercoin_digits = 6;
429
430
  if (ptr < end && IsDigit(val[ptr]))
430
431
  {
431
432
  while (ptr < end && IsDigit(val[ptr])) {
432
- if (!ProcessMantissaDigit(val[ptr], mantissa, mantissa_tzeros))
433
- return false; /* overflow */
433
+ if (peercoin_digits) {
434
+ if (!ProcessMantissaDigit(val[ptr], mantissa, mantissa_tzeros))
435
+ return false; /* overflow */
436
+ ++point_ofs;
437
+ --peercoin_digits;
438
+ }
434
439
  ++ptr;
435
- ++point_ofs;
436
440
  }
437
441
  } else return false; /* missing expected digit */
438
442
  }
src/util/system.cpp CHANGED
@@ -90,7 +90,7 @@
90
90
  // Application startup time (used for uptime calculation)
91
91
  const int64_t nStartupTime = GetTime();
92
92
 
93
- const char * const BITCOIN_CONF_FILENAME = "bitcoin.conf";
93
+ const char * const BITCOIN_CONF_FILENAME = "peercoin.conf";
94
94
  const char * const BITCOIN_SETTINGS_FILENAME = "settings.json";
95
95
 
96
96
  ArgsManager gArgs;
@@ -775,7 +775,7 @@ static std::string FormatException(const std::exception* pex, const char* pszThr
775
775
  char pszModule[MAX_PATH] = "";
776
776
  GetModuleFileNameA(nullptr, pszModule, sizeof(pszModule));
777
777
  #else
778
- const char* pszModule = "bitcoin";
778
+ const char* pszModule = "peercoin";
779
779
  #endif
780
780
  if (pex)
781
781
  return strprintf(
@@ -794,12 +794,13 @@ void PrintExceptionContinue(const std::exception* pex, const char* pszThread)
794
794
 
795
795
  fs::path GetDefaultDataDir()
796
796
  {
797
- // Windows: C:\Users\Username\AppData\Roaming\Bitcoin
798
- // macOS: ~/Library/Application Support/Bitcoin
799
- // Unix-like: ~/.bitcoin
797
+ // Windows < Vista: C:\Documents and Settings\Username\Application Data\Peercoin
798
+ // Windows >= Vista: C:\Users\Username\AppData\Roaming\Peercoin
799
+ // Mac: ~/Library/Application Support/Peercoin
800
+ // Unix: ~/.peercoin
800
801
  #ifdef WIN32
801
802
  // Windows
802
- return GetSpecialFolderPath(CSIDL_APPDATA) / "Bitcoin";
803
+ return GetSpecialFolderPath(CSIDL_APPDATA) / "Peercoin";
803
804
  #else
804
805
  fs::path pathRet;
805
806
  char* pszHome = getenv("HOME");
@@ -808,11 +809,11 @@ fs::path GetDefaultDataDir()
808
809
  else
809
810
  pathRet = fs::path(pszHome);
810
811
  #ifdef MAC_OSX
811
- // macOS
812
- return pathRet / "Library/Application Support/Bitcoin";
812
+ // Mac
813
+ return pathRet / "Library/Application Support/Peercoin";
813
814
  #else
814
- // Unix-like
815
- return pathRet / ".bitcoin";
815
+ // Unix
816
+ return pathRet / ".peercoin";
816
817
  #endif
817
818
  #endif
818
819
  }
src/validation.cpp CHANGED
@@ -16,18 +16,18 @@
16
16
  #include <consensus/tx_verify.h>
17
17
  #include <consensus/validation.h>
18
18
  #include <cuckoocache.h>
19
- #include <deploymentstatus.h>
20
19
  #include <flatfile.h>
21
20
  #include <hash.h>
22
21
  #include <index/blockfilterindex.h>
22
+ #include <index/txindex.h>
23
23
  #include <logging.h>
24
24
  #include <logging/timer.h>
25
+ #include <net.h>
25
26
  #include <node/blockstorage.h>
26
27
  #include <node/coinstats.h>
27
28
  #include <node/ui_interface.h>
28
29
  #include <node/utxo_snapshot.h>
29
30
  #include <policy/policy.h>
30
- #include <policy/rbf.h>
31
31
  #include <policy/settings.h>
32
32
  #include <pow.h>
33
33
  #include <primitives/block.h>
@@ -47,7 +47,6 @@
47
47
  #include <util/check.h> // For NDEBUG compile time check
48
48
  #include <util/hasher.h>
49
49
  #include <util/moneystr.h>
50
- #include <util/rbf.h>
51
50
  #include <util/strencodings.h>
52
51
  #include <util/system.h>
53
52
  #include <util/trace.h>
@@ -58,6 +57,10 @@
58
57
  #include <algorithm>
59
58
  #include <numeric>
60
59
  #include <optional>
60
+ #include <kernel.h>
61
+ #include <bignum.h>
62
+ #include <wallet/wallet.h>
63
+
61
64
  #include <string>
62
65
 
63
66
  #include <boost/algorithm/string/replace.hpp>
@@ -74,12 +77,8 @@ using node::ReadBlockFromDisk;
74
77
  using node::SnapshotMetadata;
75
78
  using node::UNDOFILE_CHUNK_SIZE;
76
79
  using node::UndoReadFromDisk;
77
- using node::UnlinkPrunedFiles;
78
- using node::fHavePruned;
79
80
  using node::fImporting;
80
- using node::fPruneMode;
81
81
  using node::fReindex;
82
- using node::nPruneTarget;
83
82
 
84
83
  #define MICRO 0.000001
85
84
  #define MILLI 0.001
@@ -109,8 +108,8 @@ const std::vector<std::string> CHECKLEVEL_DOC {
109
108
 
110
109
  bool CBlockIndexWorkComparator::operator()(const CBlockIndex *pa, const CBlockIndex *pb) const {
111
110
  // First sort by most total work, ...
112
- if (pa->nChainWork > pb->nChainWork) return false;
113
- if (pa->nChainWork < pb->nChainWork) return true;
111
+ if (pa->nChainTrust > pb->nChainTrust) return false;
112
+ if (pa->nChainTrust < pb->nChainTrust) return true;
114
113
 
115
114
  // ... then by earliest time received, ...
116
115
  if (pa->nSequenceId < pb->nSequenceId) return false;
@@ -125,6 +124,7 @@ bool CBlockIndexWorkComparator::operator()(const CBlockIndex *pa, const CBlockIn
125
124
  return false;
126
125
  }
127
126
 
127
+ uint256 vStakeSeen[1024];
128
128
  /**
129
129
  * Mutex to guard access to validation specific variables, such as reading
130
130
  * or changing the chainstate.
@@ -150,8 +150,7 @@ int64_t nMaxTipAge = DEFAULT_MAX_TIP_AGE;
150
150
  uint256 hashAssumeValid;
151
151
  arith_uint256 nMinimumChainWork;
152
152
 
153
- CFeeRate minRelayTxFee = CFeeRate(DEFAULT_MIN_RELAY_TX_FEE);
154
-
153
+ CTxMemPool mempool;
155
154
  CBlockIndex* CChainState::FindForkInGlobalIndex(const CBlockLocator& locator) const
156
155
  {
157
156
  AssertLockHeld(cs_main);
@@ -301,18 +300,6 @@ static void LimitMempoolSize(CTxMemPool& pool, CCoinsViewCache& coins_cache, siz
301
300
  coins_cache.Uncache(removed);
302
301
  }
303
302
 
304
- static bool IsCurrentForFeeEstimation(CChainState& active_chainstate) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
305
- {
306
- AssertLockHeld(cs_main);
307
- if (active_chainstate.IsInitialBlockDownload())
308
- return false;
309
- if (active_chainstate.m_chain.Tip()->GetBlockTime() < count_seconds(GetTime<std::chrono::seconds>() - MAX_FEE_ESTIMATION_TIP_AGE))
310
- return false;
311
- if (active_chainstate.m_chain.Height() < pindexBestHeader->nHeight - 1)
312
- return false;
313
- return true;
314
- }
315
-
316
303
  void CChainState::MaybeUpdateMempoolForReorg(
317
304
  DisconnectedBlockTransactions& disconnectpool,
318
305
  bool fAddToMempool)
@@ -331,7 +318,7 @@ void CChainState::MaybeUpdateMempoolForReorg(
331
318
  auto it = disconnectpool.queuedTx.get<insertion_order>().rbegin();
332
319
  while (it != disconnectpool.queuedTx.get<insertion_order>().rend()) {
333
320
  // ignore validation errors in resurrected transactions
334
- if (!fAddToMempool || (*it)->IsCoinBase() ||
321
+ if (!fAddToMempool || (*it)->IsCoinBase() || (*it)->IsCoinStake() ||
335
322
  AcceptToMemoryPool(*this, *it, GetTime(),
336
323
  /*bypass_limits=*/true, /*test_accept=*/false).m_result_type !=
337
324
  MempoolAcceptResult::ResultType::VALID) {
@@ -423,7 +410,7 @@ static bool CheckInputsFromMempoolAndCache(const CTransaction& tx, TxValidationS
423
410
  AssertLockHeld(cs_main);
424
411
  AssertLockHeld(pool.cs);
425
412
 
426
- assert(!tx.IsCoinBase());
413
+ assert(!tx.IsCoinBase() && !tx.IsCoinStake());
427
414
  for (const CTxIn& txin : tx.vin) {
428
415
  const Coin& coin = view.AccessCoin(txin.prevout);
429
416
 
@@ -598,9 +585,6 @@ private:
598
585
  // only tests that are fast should be done here (to avoid CPU DoS).
599
586
  bool PreChecks(ATMPArgs& args, Workspace& ws) EXCLUSIVE_LOCKS_REQUIRED(cs_main, m_pool.cs);
600
587
 
601
- // Run checks for mempool replace-by-fee.
602
- bool ReplacementChecks(Workspace& ws) EXCLUSIVE_LOCKS_REQUIRED(cs_main, m_pool.cs);
603
-
604
588
  // Enforce package mempool ancestor/descendant limits (distinct from individual
605
589
  // ancestor/descendant limits done in PreChecks).
606
590
  bool PackageMempoolChecks(const std::vector<CTransactionRef>& txns,
@@ -629,22 +613,6 @@ private:
629
613
  std::map<const uint256, const MempoolAcceptResult>& results)
630
614
  EXCLUSIVE_LOCKS_REQUIRED(cs_main, m_pool.cs);
631
615
 
632
- // Compare a package's feerate against minimum allowed.
633
- bool CheckFeeRate(size_t package_size, CAmount package_fee, TxValidationState& state) EXCLUSIVE_LOCKS_REQUIRED(::cs_main, m_pool.cs)
634
- {
635
- AssertLockHeld(::cs_main);
636
- AssertLockHeld(m_pool.cs);
637
- CAmount mempoolRejectFee = m_pool.GetMinFee(gArgs.GetIntArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000).GetFee(package_size);
638
- if (mempoolRejectFee > 0 && package_fee < mempoolRejectFee) {
639
- return state.Invalid(TxValidationResult::TX_MEMPOOL_POLICY, "mempool min fee not met", strprintf("%d < %d", package_fee, mempoolRejectFee));
640
- }
641
-
642
- if (package_fee < ::minRelayTxFee.GetFee(package_size)) {
643
- return state.Invalid(TxValidationResult::TX_MEMPOOL_POLICY, "min relay fee not met", strprintf("%d < %d", package_fee, ::minRelayTxFee.GetFee(package_size)));
644
- }
645
- return true;
646
- }
647
-
648
616
  private:
649
617
  CTxMemPool& m_pool;
650
618
  CCoinsViewCache m_view;
@@ -660,9 +628,6 @@ private:
660
628
  // in-mempool conflicts; see below).
661
629
  size_t m_limit_descendants;
662
630
  size_t m_limit_descendant_size;
663
-
664
- /** Whether the transaction(s) would replace any mempool transactions. If so, RBF rules apply. */
665
- bool m_rbf{false};
666
631
  };
667
632
 
668
633
  bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
@@ -675,7 +640,6 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
675
640
 
676
641
  // Copy/alias what we need out of args
677
642
  const int64_t nAcceptTime = args.m_accept_time;
678
- const bool bypass_limits = args.m_bypass_limits;
679
643
  std::vector<COutPoint>& coins_to_uncache = args.m_coins_to_uncache;
680
644
 
681
645
  // Alias what we need out of ws
@@ -685,9 +649,13 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
685
649
  if (!CheckTransaction(tx, state)) {
686
650
  return false; // state filled in by CheckTransaction
687
651
  }
652
+ // Time (prevent mempool memory exhaustion attack)
653
+ // moved from CheckTransaction() to here, because it makes no sense to make GetAdjustedTime() a part of the consensus rules - user can set his clock to whatever he wishes.
654
+ if (tx.nTime > GetAdjustedTime() + (IsProtocolV09(GetAdjustedTime()) ? MAX_FUTURE_BLOCK_TIME : MAX_FUTURE_BLOCK_TIME_PREV9))
655
+ return state.Invalid(TxValidationResult::TX_CONSENSUS, "timestamp-too-far");
688
656
 
689
657
  // Coinbase is only valid in a block, not as a loose transaction
690
- if (tx.IsCoinBase())
658
+ if (tx.IsCoinBase() || tx.IsCoinStake())
691
659
  return state.Invalid(TxValidationResult::TX_CONSENSUS, "coinbase");
692
660
 
693
661
  // Rather not work on nonstandard transactions (unless -testnet/-regtest)
@@ -722,25 +690,8 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
722
690
  {
723
691
  const CTransaction* ptxConflicting = m_pool.GetConflictTx(txin.prevout);
724
692
  if (ptxConflicting) {
725
- if (!args.m_allow_bip125_replacement) {
726
- // Transaction conflicts with a mempool tx, but we're not allowing replacements.
727
- return state.Invalid(TxValidationResult::TX_MEMPOOL_POLICY, "bip125-replacement-disallowed");
728
- }
729
- if (!ws.m_conflicts.count(ptxConflicting->GetHash()))
730
- {
731
- // Transactions that don't explicitly signal replaceability are
732
- // *not* replaceable with the current logic, even if one of their
733
- // unconfirmed ancestors signals replaceability. This diverges
734
- // from BIP125's inherited signaling description (see CVE-2021-31876).
735
- // Applications relying on first-seen mempool behavior should
736
- // check all unconfirmed ancestors; otherwise an opt-in ancestor
737
- // might be replaced, causing removal of this descendant.
738
- if (!SignalsOptInRBF(*ptxConflicting)) {
739
- return state.Invalid(TxValidationResult::TX_MEMPOOL_POLICY, "txn-mempool-conflict");
740
- }
741
-
742
- ws.m_conflicts.insert(ptxConflicting->GetHash());
743
- }
693
+ // Disable replacement feature for now
694
+ return state.Invalid(TxValidationResult::TX_MEMPOOL_POLICY, "txn-mempool-conflict");
744
695
  }
745
696
  }
746
697
 
@@ -790,10 +741,12 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
790
741
  return state.Invalid(TxValidationResult::TX_PREMATURE_SPEND, "non-BIP68-final");
791
742
 
792
743
  // The mempool holds txs for the next block, so pass height+1 to CheckTxInputs
793
- if (!Consensus::CheckTxInputs(tx, state, m_view, m_active_chainstate.m_chain.Height() + 1, ws.m_base_fees)) {
744
+ if (!Consensus::CheckTxInputs(tx, state, m_view, m_active_chainstate.m_chain.Height() + 1, ws.m_base_fees, Params().GetConsensus(), tx.nTime ? tx.nTime : GetAdjustedTime())) {
794
745
  return false; // state filled in by CheckTxInputs
795
746
  }
796
747
 
748
+ if (ws.m_base_fees < GetMinFee(tx, tx.nTime ? tx.nTime : GetAdjustedTime()))
749
+ return state.Invalid(TxValidationResult::TX_CONSENSUS, "fee is below minimum");
797
750
  // Check for non-standard pay-to-script-hash in inputs
798
751
  if (fRequireStandard && !AreInputsStandard(tx, m_view)) {
799
752
  return state.Invalid(TxValidationResult::TX_INPUTS_NOT_STANDARD, "bad-txns-nonstandard-inputs");
@@ -814,7 +767,7 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
814
767
  bool fSpendsCoinbase = false;
815
768
  for (const CTxIn &txin : tx.vin) {
816
769
  const Coin &coin = m_view.AccessCoin(txin.prevout);
817
- if (coin.IsCoinBase()) {
770
+ if (coin.IsCoinBase() || coin.IsCoinStake()) {
818
771
  fSpendsCoinbase = true;
819
772
  break;
820
773
  }
@@ -828,46 +781,6 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
828
781
  return state.Invalid(TxValidationResult::TX_NOT_STANDARD, "bad-txns-too-many-sigops",
829
782
  strprintf("%d", nSigOpsCost));
830
783
 
831
- // No transactions are allowed below minRelayTxFee except from disconnected
832
- // blocks
833
- if (!bypass_limits && !CheckFeeRate(ws.m_vsize, ws.m_modified_fees, state)) return false;
834
-
835
- ws.m_iters_conflicting = m_pool.GetIterSet(ws.m_conflicts);
836
- // Calculate in-mempool ancestors, up to a limit.
837
- if (ws.m_conflicts.size() == 1) {
838
- // In general, when we receive an RBF transaction with mempool conflicts, we want to know whether we
839
- // would meet the chain limits after the conflicts have been removed. However, there isn't a practical
840
- // way to do this short of calculating the ancestor and descendant sets with an overlay cache of
841
- // changed mempool entries. Due to both implementation and runtime complexity concerns, this isn't
842
- // very realistic, thus we only ensure a limited set of transactions are RBF'able despite mempool
843
- // conflicts here. Importantly, we need to ensure that some transactions which were accepted using
844
- // the below carve-out are able to be RBF'ed, without impacting the security the carve-out provides
845
- // for off-chain contract systems (see link in the comment below).
846
- //
847
- // Specifically, the subset of RBF transactions which we allow despite chain limits are those which
848
- // conflict directly with exactly one other transaction (but may evict children of said transaction),
849
- // and which are not adding any new mempool dependencies. Note that the "no new mempool dependencies"
850
- // check is accomplished later, so we don't bother doing anything about it here, but if BIP 125 is
851
- // amended, we may need to move that check to here instead of removing it wholesale.
852
- //
853
- // Such transactions are clearly not merging any existing packages, so we are only concerned with
854
- // ensuring that (a) no package is growing past the package size (not count) limits and (b) we are
855
- // not allowing something to effectively use the (below) carve-out spot when it shouldn't be allowed
856
- // to.
857
- //
858
- // To check these we first check if we meet the RBF criteria, above, and increment the descendant
859
- // limits by the direct conflict and its descendants (as these are recalculated in
860
- // CalculateMempoolAncestors by assuming the new transaction being added is a new descendant, with no
861
- // removals, of each parent's existing dependent set). The ancestor count limits are unmodified (as
862
- // the ancestor limits should be the same for both our new transaction and any conflicts).
863
- // We don't bother incrementing m_limit_descendants by the full removal count as that limit never comes
864
- // into force here (as we're only adding a single transaction).
865
- assert(ws.m_iters_conflicting.size() == 1);
866
- CTxMemPool::txiter conflict = *ws.m_iters_conflicting.begin();
867
-
868
- m_limit_descendants += 1;
869
- m_limit_descendant_size += conflict->GetSizeWithDescendants();
870
- }
871
784
 
872
785
  std::string errString;
873
786
  if (!m_pool.CalculateMemPoolAncestors(*entry, ws.m_ancestors, m_limit_ancestors, m_limit_ancestor_size, m_limit_descendants, m_limit_descendant_size, errString)) {
@@ -891,63 +804,6 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
891
804
  }
892
805
  }
893
806
 
894
- // A transaction that spends outputs that would be replaced by it is invalid. Now
895
- // that we have the set of all ancestors we can detect this
896
- // pathological case by making sure ws.m_conflicts and ws.m_ancestors don't
897
- // intersect.
898
- if (const auto err_string{EntriesAndTxidsDisjoint(ws.m_ancestors, ws.m_conflicts, hash)}) {
899
- // We classify this as a consensus error because a transaction depending on something it
900
- // conflicts with would be inconsistent.
901
- return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-txns-spends-conflicting-tx", *err_string);
902
- }
903
-
904
- m_rbf = !ws.m_conflicts.empty();
905
- return true;
906
- }
907
-
908
- bool MemPoolAccept::ReplacementChecks(Workspace& ws)
909
- {
910
- AssertLockHeld(cs_main);
911
- AssertLockHeld(m_pool.cs);
912
-
913
- const CTransaction& tx = *ws.m_ptx;
914
- const uint256& hash = ws.m_hash;
915
- TxValidationState& state = ws.m_state;
916
-
917
- CFeeRate newFeeRate(ws.m_modified_fees, ws.m_vsize);
918
- // The replacement transaction must have a higher feerate than its direct conflicts.
919
- // - The motivation for this check is to ensure that the replacement transaction is preferable for
920
- // block-inclusion, compared to what would be removed from the mempool.
921
- // - This logic predates ancestor feerate-based transaction selection, which is why it doesn't
922
- // consider feerates of descendants.
923
- // - Note: Ancestor feerate-based transaction selection has made this comparison insufficient to
924
- // guarantee that this is incentive-compatible for miners, because it is possible for a
925
- // descendant transaction of a direct conflict to pay a higher feerate than the transaction that
926
- // might replace them, under these rules.
927
- if (const auto err_string{PaysMoreThanConflicts(ws.m_iters_conflicting, newFeeRate, hash)}) {
928
- return state.Invalid(TxValidationResult::TX_MEMPOOL_POLICY, "insufficient fee", *err_string);
929
- }
930
-
931
- // Calculate all conflicting entries and enforce BIP125 Rule #5.
932
- if (const auto err_string{GetEntriesForConflicts(tx, m_pool, ws.m_iters_conflicting, ws.m_all_conflicting)}) {
933
- return state.Invalid(TxValidationResult::TX_MEMPOOL_POLICY,
934
- "too many potential replacements", *err_string);
935
- }
936
- // Enforce BIP125 Rule #2.
937
- if (const auto err_string{HasNoNewUnconfirmed(tx, m_pool, ws.m_iters_conflicting)}) {
938
- return state.Invalid(TxValidationResult::TX_MEMPOOL_POLICY,
939
- "replacement-adds-unconfirmed", *err_string);
940
- }
941
- // Check if it's economically rational to mine this transaction rather than the ones it
942
- // replaces and pays for its own relay fees. Enforce BIP125 Rules #3 and #4.
943
- for (CTxMemPool::txiter it : ws.m_all_conflicting) {
944
- ws.m_conflicting_fees += it->GetModifiedFee();
945
- ws.m_conflicting_size += it->GetTxSize();
946
- }
947
- if (const auto err_string{PaysForRBF(ws.m_conflicting_fees, ws.m_modified_fees, ws.m_vsize,
948
- ::incrementalRelayFee, hash)}) {
949
- return state.Invalid(TxValidationResult::TX_MEMPOOL_POLICY, "insufficient fee", *err_string);
950
- }
951
807
  return true;
952
808
  }
953
809
 
@@ -977,7 +833,16 @@ bool MemPoolAccept::PolicyScriptChecks(const ATMPArgs& args, Workspace& ws)
977
833
  const CTransaction& tx = *ws.m_ptx;
978
834
  TxValidationState& state = ws.m_state;
979
835
 
980
- constexpr unsigned int scriptVerifyFlags = STANDARD_SCRIPT_VERIFY_FLAGS;
836
+ unsigned int scriptVerifyFlags = STANDARD_SCRIPT_VERIFY_FLAGS;
837
+
838
+ // peercoin: if transaction is after version 0.8 fork, verify SCRIPT_VERIFY_LOW_S
839
+ // ppcTODO move back to policy.h after 0.8 is active
840
+ //if (IsBTC16BIPsEnabled(tx.nTime))
841
+ // scriptVerifyFlags &= SCRIPT_VERIFY_LOW_S;
842
+
843
+ // peercoin allow taproot after fork
844
+ //if (IsProtocolV12(tx.nTime))
845
+ // scriptVerifyFlags &= SCRIPT_VERIFY_TAPROOT;
981
846
 
982
847
  // Check input scripts and signatures.
983
848
  // This is done last to help prevent CPU exhaustion denial-of-service attacks.
@@ -1036,35 +901,14 @@ bool MemPoolAccept::Finalize(const ATMPArgs& args, Workspace& ws)
1036
901
  {
1037
902
  AssertLockHeld(cs_main);
1038
903
  AssertLockHeld(m_pool.cs);
1039
- const CTransaction& tx = *ws.m_ptx;
1040
904
  const uint256& hash = ws.m_hash;
1041
905
  TxValidationState& state = ws.m_state;
1042
906
  const bool bypass_limits = args.m_bypass_limits;
1043
907
 
1044
908
  std::unique_ptr<CTxMemPoolEntry>& entry = ws.m_entry;
1045
909
 
1046
- // Remove conflicting transactions from the mempool
1047
- for (CTxMemPool::txiter it : ws.m_all_conflicting)
1048
- {
1049
- LogPrint(BCLog::MEMPOOL, "replacing tx %s with %s for %s additional fees, %d delta bytes\n",
1050
- it->GetTx().GetHash().ToString(),
1051
- hash.ToString(),
1052
- FormatMoney(ws.m_modified_fees - ws.m_conflicting_fees),
1053
- (int)entry->GetTxSize() - (int)ws.m_conflicting_size);
1054
- ws.m_replaced_transactions.push_back(it->GetSharedTx());
1055
- }
1056
- m_pool.RemoveStaged(ws.m_all_conflicting, false, MemPoolRemovalReason::REPLACED);
1057
-
1058
- // This transaction should only count for fee estimation if:
1059
- // - it's not being re-added during a reorg which bypasses typical mempool fee limits
1060
- // - the node is not behind
1061
- // - the transaction is not dependent on any other transactions in the mempool
1062
- // - it's not part of a package. Since package relay is not currently supported, this
1063
- // transaction has not necessarily been accepted to miners' mempools.
1064
- bool validForFeeEstimation = !bypass_limits && !args.m_package_submission && IsCurrentForFeeEstimation(m_active_chainstate) && m_pool.HasNoInputsOf(tx);
1065
-
1066
910
  // Store transaction in memory
1067
- m_pool.addUnchecked(*entry, ws.m_ancestors, validForFeeEstimation);
911
+ m_pool.addUnchecked(*entry, ws.m_ancestors);
1068
912
 
1069
913
  // trim mempool and check if tx was trimmed
1070
914
  // If we are validating a package, don't trim here because we could evict a previous transaction
@@ -1162,8 +1006,6 @@ MempoolAcceptResult MemPoolAccept::AcceptSingleTransaction(const CTransactionRef
1162
1006
 
1163
1007
  if (!PreChecks(args, ws)) return MempoolAcceptResult::Failure(ws.m_state);
1164
1008
 
1165
- if (m_rbf && !ReplacementChecks(ws)) return MempoolAcceptResult::Failure(ws.m_state);
1166
-
1167
1009
  // Perform the inexpensive checks first and avoid hashing and signature verification unless
1168
1010
  // those checks pass, to mitigate CPU exhaustion denial-of-service attacks.
1169
1011
  if (!PolicyScriptChecks(args, ws)) return MempoolAcceptResult::Failure(ws.m_state);
@@ -1414,16 +1256,67 @@ PackageMempoolAcceptResult ProcessNewPackage(CChainState& active_chainstate, CTx
1414
1256
  return result;
1415
1257
  }
1416
1258
 
1417
- CAmount GetBlockSubsidy(int nHeight, const Consensus::Params& consensusParams)
1259
+ int64_t GetProofOfWorkReward(unsigned int nBits, uint32_t nTime)
1418
1260
  {
1419
- int halvings = nHeight / consensusParams.nSubsidyHalvingInterval;
1420
- // Force block reward to zero when right shift is undefined.
1421
- if (halvings >= 64)
1422
- return 0;
1423
-
1424
- CAmount nSubsidy = 50 * COIN;
1425
- // Subsidy is cut in half every 210,000 blocks which will occur approximately every 4 years.
1426
- nSubsidy >>= halvings;
1261
+ CBigNum bnSubsidyLimit = MAX_MINT_PROOF_OF_WORK;
1262
+ CBigNum bnTarget;
1263
+ bnTarget.SetCompact(nBits);
1264
+ CBigNum bnTargetLimit(Params().GetConsensus().powLimit);
1265
+ bnTargetLimit.SetCompact(bnTargetLimit.GetCompact());
1266
+
1267
+ // peercoin: subsidy is cut in half every 16x multiply of difficulty
1268
+ // A reasonably continuous curve is used to avoid shock to market
1269
+ // (nSubsidyLimit / nSubsidy) ** 4 == bnProofOfWorkLimit / bnTarget
1270
+ CBigNum bnLowerBound = CENT;
1271
+ CBigNum bnUpperBound = bnSubsidyLimit;
1272
+ while (bnLowerBound + CENT <= bnUpperBound)
1273
+ {
1274
+ CBigNum bnMidValue = (bnLowerBound + bnUpperBound) / 2;
1275
+ if (gArgs.GetBoolArg("-printcreation", false))
1276
+ LogPrintf("%s: lower=%lld upper=%lld mid=%lld\n", __func__, bnLowerBound.getuint64(), bnUpperBound.getuint64(), bnMidValue.getuint64());
1277
+ if (bnMidValue * bnMidValue * bnMidValue * bnMidValue * bnTargetLimit > bnSubsidyLimit * bnSubsidyLimit * bnSubsidyLimit * bnSubsidyLimit * bnTarget)
1278
+ bnUpperBound = bnMidValue;
1279
+ else
1280
+ bnLowerBound = bnMidValue;
1281
+ }
1282
+
1283
+ int64_t nSubsidy = bnUpperBound.getuint64();
1284
+ nSubsidy = (nSubsidy / CENT) * CENT;
1285
+
1286
+ nSubsidy = std::min(nSubsidy, IsProtocolV10(nTime) ? MAX_MINT_PROOF_OF_WORK_V10 : MAX_MINT_PROOF_OF_WORK);
1287
+
1288
+ if (gArgs.GetBoolArg("-printcreation", false))
1289
+ LogPrintf("%s: create=%s nBits=0x%08x nSubsidy=%lld\n", __func__, FormatMoney(nSubsidy), nBits, nSubsidy);
1290
+
1291
+ return nSubsidy;
1292
+ }
1293
+
1294
+ // peercoin: miner's coin stake is rewarded based on coin age spent (coin-days)
1295
+ int64_t GetProofOfStakeReward(int64_t nCoinAge, uint32_t nTime, uint64_t nMoneySupply)
1296
+ {
1297
+ static int64_t nRewardCoinYear = CENT; // creation amount per coin-year
1298
+ int64_t nSubsidy = nCoinAge * 33 / (365 * 33 + 8) * nRewardCoinYear;
1299
+
1300
+ if (IsProtocolV09(nTime)) {
1301
+ // rfc18
1302
+ // YearlyBlocks = ((365 * 33 + 8) / 33) * 1440 / 10
1303
+ // some efforts not to lose precision
1304
+ CBigNum bnInflationAdjustment = nMoneySupply;
1305
+ bnInflationAdjustment *= 25 * 33;
1306
+ bnInflationAdjustment /= 10000 * 144;
1307
+ bnInflationAdjustment /= (365 * 33 + 8);
1308
+
1309
+ uint64_t nInflationAdjustment = bnInflationAdjustment.getuint64();
1310
+ uint64_t nSubsidyNew = (nSubsidy * 3) + nInflationAdjustment;
1311
+
1312
+ if (gArgs.GetBoolArg("-printcreation", false))
1313
+ LogPrintf("%s: money supply %ld, inflation adjustment %f, old subsidy %ld, new subsidy %ld\n", __func__, nMoneySupply, nInflationAdjustment/1000000.0, nSubsidy, nSubsidyNew);
1314
+
1315
+ nSubsidy = nSubsidyNew;
1316
+ }
1317
+
1318
+ if (gArgs.GetBoolArg("-printcreation", false))
1319
+ LogPrintf("%s: create=%s nCoinAge=%lld\n", __func__, FormatMoney(nSubsidy), nCoinAge);
1427
1320
  return nSubsidy;
1428
1321
  }
1429
1322
 
@@ -1492,7 +1385,7 @@ bool CChainState::IsInitialBlockDownload() const
1492
1385
  return true;
1493
1386
  if (m_chain.Tip() == nullptr)
1494
1387
  return true;
1495
- if (m_chain.Tip()->nChainWork < nMinimumChainWork)
1388
+ if (m_chain.Tip()->nChainTrust < nMinimumChainWork)
1496
1389
  return true;
1497
1390
  if (m_chain.Tip()->GetBlockTime() < (GetTime() - nMaxTipAge))
1498
1391
  return true;
@@ -1501,9 +1394,11 @@ bool CChainState::IsInitialBlockDownload() const
1501
1394
  return false;
1502
1395
  }
1503
1396
 
1504
- static void AlertNotify(const std::string& strMessage)
1397
+
1398
+ void AlertNotify(const std::string& strMessage, bool fUpdateUI)
1505
1399
  {
1506
- uiInterface.NotifyAlertChanged();
1400
+ if (fUpdateUI)
1401
+ uiInterface.NotifyAlertChanged(uint256(), CT_UPDATED); // peercoin: we are using arguments that will have no effects in updateAlert()
1507
1402
  #if HAVE_SYSTEM
1508
1403
  std::string strCmd = gArgs.GetArg("-alertnotify", "");
1509
1404
  if (strCmd.empty()) return;
@@ -1531,7 +1426,7 @@ void CChainState::CheckForkWarningConditions()
1531
1426
  return;
1532
1427
  }
1533
1428
 
1534
- if (m_chainman.m_best_invalid && m_chainman.m_best_invalid->nChainWork > m_chain.Tip()->nChainWork + (GetBlockProof(*m_chain.Tip()) * 6)) {
1429
+ if (m_chainman.m_best_invalid && m_chainman.m_best_invalid->nChainTrust > m_chain.Tip()->nChainTrust + (GetBlockTrust(*m_chain.Tip()) * 6)) {
1535
1430
  LogPrintf("%s: Warning: Found invalid chain at least ~6 blocks longer than our best chain.\nChain state database corruption likely.\n", __func__);
1536
1431
  SetfLargeWorkInvalidChainFound(true);
1537
1432
  } else {
@@ -1543,21 +1438,25 @@ void CChainState::CheckForkWarningConditions()
1543
1438
  void CChainState::InvalidChainFound(CBlockIndex* pindexNew)
1544
1439
  {
1545
1440
  AssertLockHeld(cs_main);
1546
- if (!m_chainman.m_best_invalid || pindexNew->nChainWork > m_chainman.m_best_invalid->nChainWork) {
1441
+ if (!m_chainman.m_best_invalid || pindexNew->nChainTrust > m_chainman.m_best_invalid->nChainTrust) {
1547
1442
  m_chainman.m_best_invalid = pindexNew;
1548
1443
  }
1549
1444
  if (pindexBestHeader != nullptr && pindexBestHeader->GetAncestor(pindexNew->nHeight) == pindexNew) {
1550
1445
  pindexBestHeader = m_chain.Tip();
1551
1446
  }
1552
1447
 
1553
- LogPrintf("%s: invalid block=%s height=%d log2_work=%f date=%s\n", __func__,
1448
+ LogPrintf("%s: invalid block=%s height=%d log2_trust=%.8g moneysupply=%s date=%s moneysupply=%s\n", __func__,
1554
1449
  pindexNew->GetBlockHash().ToString(), pindexNew->nHeight,
1555
- log(pindexNew->nChainWork.getdouble())/log(2.0), FormatISO8601DateTime(pindexNew->GetBlockTime()));
1450
+ log(pindexNew->nChainTrust.getdouble())/log(2.0),
1451
+ FormatMoney(m_chain.Tip()->nMoneySupply),
1452
+ FormatISO8601DateTime(pindexNew->GetBlockTime()),
1453
+ FormatMoney(pindexNew->nMoneySupply));
1556
1454
  CBlockIndex *tip = m_chain.Tip();
1557
1455
  assert (tip);
1558
- LogPrintf("%s: current best=%s height=%d log2_work=%f date=%s\n", __func__,
1559
- tip->GetBlockHash().ToString(), m_chain.Height(), log(tip->nChainWork.getdouble())/log(2.0),
1560
- FormatISO8601DateTime(tip->GetBlockTime()));
1456
+ LogPrintf("%s: current best=%s height=%d log2_trust=%.8g moneysupply=%s date=%s moneysupply=%s\n", __func__,
1457
+ tip->GetBlockHash().ToString(), m_chain.Height(), log(tip->nChainTrust.getdouble())/log(2.0),
1458
+ FormatMoney(tip->nMoneySupply),
1459
+ FormatISO8601DateTime(tip->GetBlockTime()), FormatMoney(pindexNew->nMoneySupply));
1561
1460
  CheckForkWarningConditions();
1562
1461
  }
1563
1462
 
@@ -1575,7 +1474,7 @@ void CChainState::InvalidBlockFound(CBlockIndex* pindex, const BlockValidationSt
1575
1474
  }
1576
1475
  }
1577
1476
 
1578
- void UpdateCoins(const CTransaction& tx, CCoinsViewCache& inputs, CTxUndo &txundo, int nHeight)
1477
+ void UpdateCoins(const CTransaction& tx, CCoinsViewCache& inputs, CTxUndo &txundo, int nHeight, bool skipZeroValue)
1579
1478
  {
1580
1479
  // mark inputs spent
1581
1480
  if (!tx.IsCoinBase()) {
@@ -1587,7 +1486,7 @@ void UpdateCoins(const CTransaction& tx, CCoinsViewCache& inputs, CTxUndo &txund
1587
1486
  }
1588
1487
  }
1589
1488
  // add outputs
1590
- AddCoins(inputs, tx, nHeight);
1489
+ AddCoins(inputs, tx, nHeight, false, skipZeroValue);
1591
1490
  }
1592
1491
 
1593
1492
  bool CScriptCheck::operator()() {
@@ -1749,6 +1648,8 @@ int ApplyTxInUndo(Coin&& undo, CCoinsViewCache& view, const COutPoint& out)
1749
1648
  if (!alternate.IsSpent()) {
1750
1649
  undo.nHeight = alternate.nHeight;
1751
1650
  undo.fCoinBase = alternate.fCoinBase;
1651
+ undo.fCoinStake = alternate.fCoinStake; // peercoin
1652
+ undo.nTime = alternate.nTime; // peercoin
1752
1653
  } else {
1753
1654
  return DISCONNECT_FAILED; // adding output for transaction without known metadata
1754
1655
  }
@@ -1758,7 +1659,7 @@ int ApplyTxInUndo(Coin&& undo, CCoinsViewCache& view, const COutPoint& out)
1758
1659
  // already checked whether an unspent coin exists above using HaveCoin, so
1759
1660
  // we don't need to guess. When fClean is false, an unspent coin already
1760
1661
  // existed and it is an overwrite.
1761
- view.AddCoin(out, std::move(undo), !fClean);
1662
+ view.AddCoin(out, std::move(undo), !fClean, false);
1762
1663
 
1763
1664
  return fClean ? DISCONNECT_OK : DISCONNECT_UNCLEAN;
1764
1665
  }
@@ -1786,15 +1687,18 @@ DisconnectResult CChainState::DisconnectBlock(const CBlock& block, const CBlockI
1786
1687
  const CTransaction &tx = *(block.vtx[i]);
1787
1688
  uint256 hash = tx.GetHash();
1788
1689
  bool is_coinbase = tx.IsCoinBase();
1690
+ bool is_coinstake = tx.IsCoinStake();
1789
1691
 
1790
1692
  // Check that all outputs are available and match the outputs in the block itself
1791
1693
  // exactly.
1792
1694
  for (size_t o = 0; o < tx.vout.size(); o++) {
1793
1695
  if (!tx.vout[o].scriptPubKey.IsUnspendable()) {
1696
+ if (IsProtocolV12(pindex) && !tx.vout[o].nValue)
1697
+ continue;
1794
1698
  COutPoint out(hash, o);
1795
1699
  Coin coin;
1796
1700
  bool is_spent = view.SpendCoin(out, &coin);
1797
- if (!is_spent || tx.vout[o] != coin.out || pindex->nHeight != coin.nHeight || is_coinbase != coin.fCoinBase) {
1701
+ if (!is_spent || tx.vout[o] != coin.out || pindex->nHeight != coin.nHeight || is_coinbase != coin.fCoinBase || is_coinstake != coin.fCoinStake) {
1798
1702
  fClean = false; // transaction output mismatch
1799
1703
  }
1800
1704
  }
@@ -1836,33 +1740,6 @@ void StopScriptCheckWorkerThreads()
1836
1740
  scriptcheckqueue.StopWorkerThreads();
1837
1741
  }
1838
1742
 
1839
- /**
1840
- * Threshold condition checker that triggers when unknown versionbits are seen on the network.
1841
- */
1842
- class WarningBitsConditionChecker : public AbstractThresholdConditionChecker
1843
- {
1844
- private:
1845
- int bit;
1846
-
1847
- public:
1848
- explicit WarningBitsConditionChecker(int bitIn) : bit(bitIn) {}
1849
-
1850
- int64_t BeginTime(const Consensus::Params& params) const override { return 0; }
1851
- int64_t EndTime(const Consensus::Params& params) const override { return std::numeric_limits<int64_t>::max(); }
1852
- int Period(const Consensus::Params& params) const override { return params.nMinerConfirmationWindow; }
1853
- int Threshold(const Consensus::Params& params) const override { return params.nRuleChangeActivationThreshold; }
1854
-
1855
- bool Condition(const CBlockIndex* pindex, const Consensus::Params& params) const override
1856
- {
1857
- return pindex->nHeight >= params.MinBIP9WarningHeight &&
1858
- ((pindex->nVersion & VERSIONBITS_TOP_MASK) == VERSIONBITS_TOP_BITS) &&
1859
- ((pindex->nVersion >> bit) & 1) != 0 &&
1860
- ((g_versionbitscache.ComputeBlockVersion(pindex->pprev, params) >> bit) & 1) == 0;
1861
- }
1862
- };
1863
-
1864
- static ThresholdConditionCache warningcache[VERSIONBITS_NUM_BITS] GUARDED_BY(cs_main);
1865
-
1866
1743
  static unsigned int GetBlockScriptFlags(const CBlockIndex* pindex, const Consensus::Params& consensusparams)
1867
1744
  {
1868
1745
  unsigned int flags = SCRIPT_VERIFY_NONE;
@@ -1881,30 +1758,26 @@ static unsigned int GetBlockScriptFlags(const CBlockIndex* pindex, const Consens
1881
1758
  }
1882
1759
 
1883
1760
  // Enforce the DERSIG (BIP66) rule
1884
- if (DeploymentActiveAt(*pindex, consensusparams, Consensus::DEPLOYMENT_DERSIG)) {
1761
+ if (pindex->pprev && IsBTC16BIPsEnabled(pindex->pprev->nTime)) {
1885
1762
  flags |= SCRIPT_VERIFY_DERSIG;
1886
1763
  }
1887
1764
 
1888
1765
  // Enforce CHECKLOCKTIMEVERIFY (BIP65)
1889
- if (DeploymentActiveAt(*pindex, consensusparams, Consensus::DEPLOYMENT_CLTV)) {
1766
+ if (IsProtocolV06(pindex->pprev)) {
1890
1767
  flags |= SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY;
1891
1768
  }
1892
1769
 
1893
- // Enforce CHECKSEQUENCEVERIFY (BIP112)
1894
- if (DeploymentActiveAt(*pindex, consensusparams, Consensus::DEPLOYMENT_CSV)) {
1895
- flags |= SCRIPT_VERIFY_CHECKSEQUENCEVERIFY;
1770
+ // Enforce BIP68 (sequence locks) and BIP112 (CHECKSEQUENCEVERIFY)
1771
+ // Enforce BIP147 NULLDUMMY (activated simultaneously with segwit)
1772
+ if (pindex->pprev && IsBTC16BIPsEnabled(pindex->pprev->nTime)) {
1773
+ flags |= SCRIPT_VERIFY_CHECKSEQUENCEVERIFY | SCRIPT_VERIFY_NULLDUMMY;
1896
1774
  }
1897
1775
 
1898
1776
  // Enforce Taproot (BIP340-BIP342)
1899
- if (DeploymentActiveAt(*pindex, consensusparams, Consensus::DEPLOYMENT_TAPROOT)) {
1777
+ if (pindex->pprev && IsProtocolV12(pindex->pprev)) {
1900
1778
  flags |= SCRIPT_VERIFY_TAPROOT;
1901
1779
  }
1902
1780
 
1903
- // Enforce BIP147 NULLDUMMY (activated simultaneously with segwit)
1904
- if (DeploymentActiveAt(*pindex, consensusparams, Consensus::DEPLOYMENT_SEGWIT)) {
1905
- flags |= SCRIPT_VERIFY_NULLDUMMY;
1906
- }
1907
-
1908
1781
  return flags;
1909
1782
  }
1910
1783
 
@@ -1918,6 +1791,80 @@ static int64_t nTimeIndex = 0;
1918
1791
  static int64_t nTimeTotal = 0;
1919
1792
  static int64_t nBlocksTotal = 0;
1920
1793
 
1794
+ // These checks can only be done when all previous block have been added.
1795
+ bool PeercoinContextualBlockChecks(const CBlock& block, BlockValidationState& state, CBlockIndex* pindex, bool fJustCheck, CChainState& chainstate)
1796
+ {
1797
+ uint256 hashProofOfStake = uint256();
1798
+ // peercoin: verify hash target and signature of coinstake tx
1799
+ if (block.IsProofOfStake() && !CheckProofOfStake(state, pindex->pprev, block.vtx[1], block.nBits, hashProofOfStake, block.vtx[1]->nTime ? block.vtx[1]->nTime : block.nTime, chainstate)) {
1800
+ LogPrintf("WARNING: %s: check proof-of-stake failed for block %s\n", __func__, block.GetHash().ToString());
1801
+ return false; // do not error here as we expect this during initial block download
1802
+ }
1803
+
1804
+ // peercoin: check for duplicity of stake
1805
+ if (block.IsProofOfStake()) {
1806
+ std::pair<COutPoint, unsigned int> proofOfStake = block.GetProofOfStake();
1807
+ if (pindex->IsProofOfStake() && proofOfStake.first == pindex->prevoutStake) {
1808
+ LogPrintf("WARNING: %s: duplicate proof-of-stake in block %s, invalidating tip\n", __func__, block.GetHash().ToString());
1809
+ chainstate.InvalidateBlock(state, pindex);
1810
+ return error("ConnectBlock() : Duplicate coinstake found");
1811
+ } else if (setStakeSeen.count(proofOfStake)) {
1812
+ LogPrintf("WARNING: %s: duplicate proof-of-stake in block %s\n", __func__, block.GetHash().ToString());
1813
+ return error("ConnectBlock() : Duplicate coinstake found");
1814
+ }
1815
+ }
1816
+
1817
+ // peercoin: compute stake entropy bit for stake modifier
1818
+ unsigned int nEntropyBit = GetStakeEntropyBit(block);
1819
+
1820
+ // peercoin: compute stake modifier
1821
+ uint64_t nStakeModifier = 0;
1822
+ bool fGeneratedStakeModifier = false;
1823
+ if (!ComputeNextStakeModifier(pindex, nStakeModifier, fGeneratedStakeModifier, chainstate))
1824
+ return error("ConnectBlock() : ComputeNextStakeModifier() failed");
1825
+
1826
+ // compute nStakeModifierChecksum begin
1827
+ unsigned int nFlagsBackup = pindex->nFlags;
1828
+ uint64_t nStakeModifierBackup = pindex->nStakeModifier;
1829
+ uint256 hashProofOfStakeBackup = pindex->hashProofOfStake;
1830
+
1831
+ // set necessary pindex fields
1832
+ if (!pindex->SetStakeEntropyBit(nEntropyBit))
1833
+ return error("ConnectBlock() : SetStakeEntropyBit() failed");
1834
+ pindex->SetStakeModifier(nStakeModifier, fGeneratedStakeModifier);
1835
+ pindex->hashProofOfStake = hashProofOfStake;
1836
+
1837
+ unsigned int nStakeModifierChecksum = GetStakeModifierChecksum(pindex);
1838
+
1839
+ // undo pindex fields
1840
+ pindex->nFlags = nFlagsBackup;
1841
+ pindex->nStakeModifier = nStakeModifierBackup;
1842
+ pindex->hashProofOfStake = hashProofOfStakeBackup;
1843
+ // compute nStakeModifierChecksum end
1844
+
1845
+ if (!CheckStakeModifierCheckpoints(pindex->nHeight, nStakeModifierChecksum))
1846
+ return error("ConnectBlock() : Rejected by stake modifier checkpoint height=%d, modifier=0x%016llx", pindex->nHeight, nStakeModifier);
1847
+
1848
+ if (fJustCheck)
1849
+ return true;
1850
+
1851
+ // write everything to index
1852
+ if (block.IsProofOfStake())
1853
+ {
1854
+ pindex->prevoutStake = block.vtx[1]->vin[0].prevout;
1855
+ pindex->nStakeTime = block.vtx[1]->nTime;
1856
+ pindex->hashProofOfStake = hashProofOfStake;
1857
+ setStakeSeen.insert(std::make_pair(pindex->prevoutStake, pindex->nTime));
1858
+ }
1859
+ if (!pindex->SetStakeEntropyBit(nEntropyBit))
1860
+ return error("ConnectBlock() : SetStakeEntropyBit() failed");
1861
+ pindex->SetStakeModifier(nStakeModifier, fGeneratedStakeModifier);
1862
+ pindex->nStakeModifierChecksum = nStakeModifierChecksum;
1863
+ chainstate.m_blockman.m_dirty_blockindex.insert(pindex); // queue a write to disk
1864
+
1865
+ return true;
1866
+ }
1867
+
1921
1868
  /** Apply the effects of this block (with given index) on the UTXO set represented by coins.
1922
1869
  * Validity checks that depend on the UTXO set are also done; ConnectBlock()
1923
1870
  * can fail if those validity checks fail (among other reasons). */
@@ -1932,6 +1879,9 @@ bool CChainState::ConnectBlock(const CBlock& block, BlockValidationState& state,
1932
1879
 
1933
1880
  int64_t nTimeStart = GetTimeMicros();
1934
1881
 
1882
+ if (pindex->nStakeModifier == 0 && pindex->nStakeModifierChecksum == 0 && !PeercoinContextualBlockChecks(block, state, pindex, fJustCheck, m_chainman.ActiveChainstate()))
1883
+ return error("%s: failed PoS check %s", __func__, state.ToString());
1884
+
1935
1885
  // Check it again in case a previous version let a bad block in
1936
1886
  // NOTE: We don't currently (re-)invoke ContextualCheckBlock() or
1937
1887
  // ContextualCheckBlockHeader() here. This means that if we add a new
@@ -1980,7 +1930,7 @@ bool CChainState::ConnectBlock(const CBlock& block, BlockValidationState& state,
1980
1930
  if (it != m_blockman.m_block_index.end()) {
1981
1931
  if (it->second->GetAncestor(pindex->nHeight) == pindex &&
1982
1932
  pindexBestHeader->GetAncestor(pindex->nHeight) == pindex &&
1983
- pindexBestHeader->nChainWork >= nMinimumChainWork) {
1933
+ pindexBestHeader->nChainTrust >= nMinimumChainWork) {
1984
1934
  // This block is a member of the assumed verified chain and an ancestor of the best header.
1985
1935
  // Script verification is skipped when connecting blocks under the
1986
1936
  // assumevalid block. Assuming the assumevalid block is valid this
@@ -2013,8 +1963,7 @@ bool CChainState::ConnectBlock(const CBlock& block, BlockValidationState& state,
2013
1963
  // Now that the whole chain is irreversibly beyond that time it is applied to all blocks except the
2014
1964
  // two in the chain that violate it. This prevents exploiting the issue against nodes during their
2015
1965
  // initial block download.
2016
- bool fEnforceBIP30 = !((pindex->nHeight==91842 && pindex->GetBlockHash() == uint256S("0x00000000000a4d0a398161ffc163c503763b1f4360639393e0e4c8e300e0caec")) ||
2017
- (pindex->nHeight==91880 && pindex->GetBlockHash() == uint256S("0x00000000000743f190a18c5577a3c2d2a1f610ae9601ac046a38084ccb7cd721")));
1966
+ bool fEnforceBIP30 = (!pindex->phashBlock); // Enforce on CreateNewBlock invocations which don't have a hash.
2018
1967
 
2019
1968
  // Once BIP34 activated it was not possible to create new duplicate coinbases and thus other than starting
2020
1969
  // with the 2 existing duplicate coinbase pairs, not possible to create overwriting txs. But by the
@@ -2090,9 +2039,9 @@ bool CChainState::ConnectBlock(const CBlock& block, BlockValidationState& state,
2090
2039
  }
2091
2040
  }
2092
2041
 
2093
- // Enforce BIP68 (sequence locks)
2042
+ // Enforce BIP68 (sequence locks) and BIP112 (CHECKSEQUENCEVERIFY)
2094
2043
  int nLockTimeFlags = 0;
2095
- if (DeploymentActiveAt(*pindex, m_params.GetConsensus(), Consensus::DEPLOYMENT_CSV)) {
2044
+ if (pindex->pprev && IsBTC16BIPsEnabled(pindex->pprev->nTime)) {
2096
2045
  nLockTimeFlags |= LOCKTIME_VERIFY_SEQUENCE;
2097
2046
  }
2098
2047
 
@@ -2114,6 +2063,8 @@ bool CChainState::ConnectBlock(const CBlock& block, BlockValidationState& state,
2114
2063
 
2115
2064
  std::vector<int> prevheights;
2116
2065
  CAmount nFees = 0;
2066
+ int64_t nValueIn = 0;
2067
+ int64_t nValueOut = 0;
2117
2068
  int nInputs = 0;
2118
2069
  int64_t nSigOpsCost = 0;
2119
2070
  blockundo.vtxundo.reserve(block.vtx.size() - 1);
@@ -2123,17 +2074,23 @@ bool CChainState::ConnectBlock(const CBlock& block, BlockValidationState& state,
2123
2074
 
2124
2075
  nInputs += tx.vin.size();
2125
2076
 
2126
- if (!tx.IsCoinBase())
2077
+ if (tx.IsCoinBase())
2078
+ nValueOut += tx.GetValueOut();
2079
+ else
2127
2080
  {
2128
2081
  CAmount txfee = 0;
2129
2082
  TxValidationState tx_state;
2130
- if (!Consensus::CheckTxInputs(tx, tx_state, view, pindex->nHeight, txfee)) {
2083
+ if (!Consensus::CheckTxInputs(tx, tx_state, view, pindex->nHeight, txfee, Params().GetConsensus(), tx.nTime ? tx.nTime : block.nTime, (pindex->pprev? pindex->pprev->nMoneySupply : 0))) {
2131
2084
  // Any transaction validation failure in ConnectBlock is a block consensus failure
2132
2085
  state.Invalid(BlockValidationResult::BLOCK_CONSENSUS,
2133
2086
  tx_state.GetRejectReason(), tx_state.GetDebugMessage());
2134
2087
  return error("%s: Consensus::CheckTxInputs: %s, %s", __func__, tx.GetHash().ToString(), state.ToString());
2135
2088
  }
2136
- nFees += txfee;
2089
+ for (unsigned int i = 0; i < tx.vin.size(); i++)
2090
+ nValueIn += view.AccessCoin(tx.vin[i].prevout).out.nValue;
2091
+ nValueOut += tx.GetValueOut();
2092
+ if (!tx.IsCoinStake())
2093
+ nFees += txfee;
2137
2094
  if (!MoneyRange(nFees)) {
2138
2095
  LogPrintf("ERROR: %s: accumulated fee in the block out of range.\n", __func__);
2139
2096
  return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-txns-accumulated-fee-outofrange");
@@ -2182,16 +2139,12 @@ bool CChainState::ConnectBlock(const CBlock& block, BlockValidationState& state,
2182
2139
  if (i > 0) {
2183
2140
  blockundo.vtxundo.push_back(CTxUndo());
2184
2141
  }
2185
- UpdateCoins(tx, view, i == 0 ? undoDummy : blockundo.vtxundo.back(), pindex->nHeight);
2142
+ UpdateCoins(tx, view, i == 0 ? undoDummy : blockundo.vtxundo.back(), pindex->nHeight, IsProtocolV12(pindex));
2186
2143
  }
2187
2144
  int64_t nTime3 = GetTimeMicros(); nTimeConnect += nTime3 - nTime2;
2188
2145
  LogPrint(BCLog::BENCH, " - Connect %u transactions: %.2fms (%.3fms/tx, %.3fms/txin) [%.2fs (%.2fms/blk)]\n", (unsigned)block.vtx.size(), MILLI * (nTime3 - nTime2), MILLI * (nTime3 - nTime2) / block.vtx.size(), nInputs <= 1 ? 0 : MILLI * (nTime3 - nTime2) / (nInputs-1), nTimeConnect * MICRO, nTimeConnect * MILLI / nBlocksTotal);
2189
2146
 
2190
- CAmount blockReward = nFees + GetBlockSubsidy(pindex->nHeight, m_params.GetConsensus());
2191
- if (block.vtx[0]->GetValueOut() > blockReward) {
2192
- LogPrintf("ERROR: ConnectBlock(): coinbase pays too much (actual=%d vs limit=%d)\n", block.vtx[0]->GetValueOut(), blockReward);
2193
- return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-cb-amount");
2194
- }
2147
+ // peercoin: coinbase reward check relocated to CheckBlock()
2195
2148
 
2196
2149
  if (!control.Wait()) {
2197
2150
  LogPrintf("ERROR: %s: CheckQueue failed\n", __func__);
@@ -2203,6 +2156,15 @@ bool CChainState::ConnectBlock(const CBlock& block, BlockValidationState& state,
2203
2156
  if (fJustCheck)
2204
2157
  return true;
2205
2158
 
2159
+ // peercoin: track money supply and mint amount info
2160
+ pindex->nMint = nValueOut - nValueIn + nFees;
2161
+ pindex->nMoneySupply = (pindex->pprev? pindex->pprev->nMoneySupply : 0) + nValueOut - nValueIn;
2162
+
2163
+ // peercoin: fees are not collected by miners as in bitcoin
2164
+ // peercoin: fees are destroyed to compensate the entire network
2165
+ if (gArgs.GetBoolArg("-printcreation", false))
2166
+ LogPrintf("%s: destroy=%s nFees=%lld\n", __func__, FormatMoney(nFees), nFees);
2167
+
2206
2168
  if (!m_blockman.WriteUndoDataForBlock(blockundo, state, pindex, m_params)) {
2207
2169
  return false;
2208
2170
  }
@@ -2272,7 +2234,6 @@ bool CChainState::FlushStateToDisk(
2272
2234
  assert(this->CanFlushToDisk());
2273
2235
  static std::chrono::microseconds nLastWrite{0};
2274
2236
  static std::chrono::microseconds nLastFlush{0};
2275
- std::set<int> setFilesToPrune;
2276
2237
  bool full_flush_completed = false;
2277
2238
 
2278
2239
  const size_t coins_count = CoinsTip().GetCacheSize();
@@ -2280,12 +2241,10 @@ bool CChainState::FlushStateToDisk(
2280
2241
 
2281
2242
  try {
2282
2243
  {
2283
- bool fFlushForPrune = false;
2284
2244
  bool fDoFullFlush = false;
2285
2245
 
2286
2246
  CoinsCacheSizeState cache_state = GetCoinsCacheSizeState();
2287
2247
  LOCK(m_blockman.cs_LastBlockFile);
2288
- if (fPruneMode && (m_blockman.m_check_for_pruning || nManualPruneHeight > 0) && !fReindex) {
2289
2248
  // make sure we don't prune above the blockfilterindexes bestblocks
2290
2249
  // pruning is height-based
2291
2250
  int last_prune = m_chain.Height(); // last height we can prune
@@ -2293,24 +2252,6 @@ bool CChainState::FlushStateToDisk(
2293
2252
  last_prune = std::max(1, std::min(last_prune, index.GetSummary().best_block_height));
2294
2253
  });
2295
2254
 
2296
- if (nManualPruneHeight > 0) {
2297
- LOG_TIME_MILLIS_WITH_CATEGORY("find files to prune (manual)", BCLog::BENCH);
2298
-
2299
- m_blockman.FindFilesToPruneManual(setFilesToPrune, std::min(last_prune, nManualPruneHeight), m_chain.Height());
2300
- } else {
2301
- LOG_TIME_MILLIS_WITH_CATEGORY("find files to prune", BCLog::BENCH);
2302
-
2303
- m_blockman.FindFilesToPrune(setFilesToPrune, m_params.PruneAfterHeight(), m_chain.Height(), last_prune, IsInitialBlockDownload());
2304
- m_blockman.m_check_for_pruning = false;
2305
- }
2306
- if (!setFilesToPrune.empty()) {
2307
- fFlushForPrune = true;
2308
- if (!fHavePruned) {
2309
- m_blockman.m_block_tree_db->WriteFlag("prunedblockfiles", true);
2310
- fHavePruned = true;
2311
- }
2312
- }
2313
- }
2314
2255
  const auto nNow = GetTime<std::chrono::microseconds>();
2315
2256
  // Avoid writing/flushing immediately after startup.
2316
2257
  if (nLastWrite.count() == 0) {
@@ -2328,7 +2269,7 @@ bool CChainState::FlushStateToDisk(
2328
2269
  // It's been very long since we flushed the cache. Do this infrequently, to optimize cache usage.
2329
2270
  bool fPeriodicFlush = mode == FlushStateMode::PERIODIC && nNow > nLastFlush + DATABASE_FLUSH_INTERVAL;
2330
2271
  // Combine all conditions that result in a full cache flush.
2331
- fDoFullFlush = (mode == FlushStateMode::ALWAYS) || fCacheLarge || fCacheCritical || fPeriodicFlush || fFlushForPrune;
2272
+ fDoFullFlush = (mode == FlushStateMode::ALWAYS) || fCacheLarge || fCacheCritical || fPeriodicFlush;
2332
2273
  // Write blocks and block index to disk.
2333
2274
  if (fDoFullFlush || fPeriodicWrite) {
2334
2275
  // Ensure we can write block index
@@ -2350,12 +2291,6 @@ bool CChainState::FlushStateToDisk(
2350
2291
  return AbortNode(state, "Failed to write to block index database");
2351
2292
  }
2352
2293
  }
2353
- // Finally remove any pruned files
2354
- if (fFlushForPrune) {
2355
- LOG_TIME_MILLIS_WITH_CATEGORY("unlink pruned files", BCLog::BENCH);
2356
-
2357
- UnlinkPrunedFiles(setFilesToPrune);
2358
- }
2359
2294
  nLastWrite = nNow;
2360
2295
  }
2361
2296
  // Flush best chain related state. This can only be done if the blocks / block index write was also done.
@@ -2376,12 +2311,11 @@ bool CChainState::FlushStateToDisk(
2376
2311
  return AbortNode(state, "Failed to write to coin database");
2377
2312
  nLastFlush = nNow;
2378
2313
  full_flush_completed = true;
2379
- TRACE5(utxocache, flush,
2314
+ TRACE4(utxocache, flush,
2380
2315
  (int64_t)(GetTimeMicros() - nNow.count()), // in microseconds (µs)
2381
2316
  (u_int32_t)mode,
2382
2317
  (u_int64_t)coins_count,
2383
- (u_int64_t)coins_mem_usage,
2384
- (bool)fFlushForPrune);
2318
+ (u_int64_t)coins_mem_usage);
2385
2319
  }
2386
2320
  }
2387
2321
  if (full_flush_completed) {
@@ -2402,25 +2336,6 @@ void CChainState::ForceFlushStateToDisk()
2402
2336
  }
2403
2337
  }
2404
2338
 
2405
- void CChainState::PruneAndFlush()
2406
- {
2407
- BlockValidationState state;
2408
- m_blockman.m_check_for_pruning = true;
2409
- if (!this->FlushStateToDisk(state, FlushStateMode::NONE)) {
2410
- LogPrintf("%s: failed to flush state (%s)\n", __func__, state.ToString());
2411
- }
2412
- }
2413
-
2414
- static void DoWarning(const bilingual_str& warning)
2415
- {
2416
- static bool fWarned = false;
2417
- SetMiscWarning(warning);
2418
- if (!fWarned) {
2419
- AlertNotify(warning.original);
2420
- fWarned = true;
2421
- }
2422
- }
2423
-
2424
2339
  /** Private helper function that concatenates warning messages. */
2425
2340
  static void AppendWarning(bilingual_str& res, const bilingual_str& warn)
2426
2341
  {
@@ -2441,7 +2356,7 @@ static void UpdateTipLog(
2441
2356
  LogPrintf("%s%s: new best=%s height=%d version=0x%08x log2_work=%f tx=%lu date='%s' progress=%f cache=%.1fMiB(%utxo)%s\n",
2442
2357
  prefix, func_name,
2443
2358
  tip->GetBlockHash().ToString(), tip->nHeight, tip->nVersion,
2444
- log(tip->nChainWork.getdouble()) / log(2.0), (unsigned long)tip->nChainTx,
2359
+ log(tip->nChainTrust.getdouble()) / log(2.0), (unsigned long)tip->nChainTx,
2445
2360
  FormatISO8601DateTime(tip->GetBlockTime()),
2446
2361
  GuessVerificationProgress(params.TxData(), tip),
2447
2362
  coins_tip.DynamicMemoryUsage() * (1.0 / (1 << 20)),
@@ -2479,19 +2394,8 @@ void CChainState::UpdateTip(const CBlockIndex* pindexNew)
2479
2394
  bilingual_str warning_messages;
2480
2395
  if (!this->IsInitialBlockDownload()) {
2481
2396
  const CBlockIndex* pindex = pindexNew;
2482
- for (int bit = 0; bit < VERSIONBITS_NUM_BITS; bit++) {
2483
- WarningBitsConditionChecker checker(bit);
2484
- ThresholdState state = checker.GetStateFor(pindex, m_params.GetConsensus(), warningcache[bit]);
2485
- if (state == ThresholdState::ACTIVE || state == ThresholdState::LOCKED_IN) {
2486
- const bilingual_str warning = strprintf(_("Unknown new rules activated (versionbit %i)"), bit);
2487
- if (state == ThresholdState::ACTIVE) {
2488
- DoWarning(warning);
2489
- } else {
2490
- AppendWarning(warning_messages, warning);
2491
- }
2492
- }
2493
- }
2494
2397
  }
2398
+
2495
2399
  UpdateTipLog(coins_tip, pindexNew, m_params, __func__, "", warning_messages.original);
2496
2400
  }
2497
2401
 
@@ -2704,7 +2608,7 @@ CBlockIndex* CChainState::FindMostWorkChain()
2704
2608
  bool fMissingData = !(pindexTest->nStatus & BLOCK_HAVE_DATA);
2705
2609
  if (fFailedChain || fMissingData) {
2706
2610
  // Candidate chain is not usable (either invalid or missing data)
2707
- if (fFailedChain && (m_chainman.m_best_invalid == nullptr || pindexNew->nChainWork > m_chainman.m_best_invalid->nChainWork)) {
2611
+ if (fFailedChain && (m_chainman.m_best_invalid == nullptr || pindexNew->nChainTrust > m_chainman.m_best_invalid->nChainTrust)) {
2708
2612
  m_chainman.m_best_invalid = pindexNew;
2709
2613
  }
2710
2614
  CBlockIndex *pindexFailed = pindexNew;
@@ -2815,7 +2719,7 @@ bool CChainState::ActivateBestChainStep(BlockValidationState& state, CBlockIndex
2815
2719
  }
2816
2720
  } else {
2817
2721
  PruneBlockIndexCandidates();
2818
- if (!pindexOldTip || m_chain.Tip()->nChainWork > pindexOldTip->nChainWork) {
2722
+ if (!pindexOldTip || m_chain.Tip()->nChainTrust > pindexOldTip->nChainTrust) {
2819
2723
  // We're in a better position than we were. Return temporarily to release the lock.
2820
2724
  fContinue = false;
2821
2725
  break;
@@ -2981,15 +2885,15 @@ bool CChainState::PreciousBlock(BlockValidationState& state, CBlockIndex* pindex
2981
2885
  AssertLockNotHeld(::cs_main);
2982
2886
  {
2983
2887
  LOCK(cs_main);
2984
- if (pindex->nChainWork < m_chain.Tip()->nChainWork) {
2888
+ if (pindex->nChainTrust < m_chain.Tip()->nChainTrust) {
2985
2889
  // Nothing to do, this block is not at the tip.
2986
2890
  return true;
2987
2891
  }
2988
- if (m_chain.Tip()->nChainWork > nLastPreciousChainwork) {
2892
+ if (m_chain.Tip()->nChainTrust > nLastPreciousChainwork) {
2989
2893
  // The chain has been extended since the last call, reset the counter.
2990
2894
  nBlockReverseSequenceId = -1;
2991
2895
  }
2992
- nLastPreciousChainwork = m_chain.Tip()->nChainWork;
2896
+ nLastPreciousChainwork = m_chain.Tip()->nChainTrust;
2993
2897
  setBlockIndexCandidates.erase(pindex);
2994
2898
  pindex->nSequenceId = nBlockReverseSequenceId;
2995
2899
  if (nBlockReverseSequenceId > std::numeric_limits<int32_t>::min()) {
@@ -3046,7 +2950,7 @@ bool CChainState::InvalidateBlock(BlockValidationState& state, CBlockIndex* pind
3046
2950
  !CBlockIndexWorkComparator()(candidate, pindex->pprev) &&
3047
2951
  candidate->IsValid(BLOCK_VALID_TRANSACTIONS) &&
3048
2952
  candidate->HaveTxsDownloaded()) {
3049
- candidate_blocks_by_work.insert(std::make_pair(candidate->nChainWork, candidate));
2953
+ candidate_blocks_by_work.insert(std::make_pair(candidate->nChainTrust, candidate));
3050
2954
  }
3051
2955
  }
3052
2956
  }
@@ -3096,7 +3000,7 @@ bool CChainState::InvalidateBlock(BlockValidationState& state, CBlockIndex* pind
3096
3000
  }
3097
3001
 
3098
3002
  // Add any equal or more work headers to setBlockIndexCandidates
3099
- auto candidate_it = candidate_blocks_by_work.lower_bound(invalid_walk_tip->pprev->nChainWork);
3003
+ auto candidate_it = candidate_blocks_by_work.lower_bound(invalid_walk_tip->pprev->nChainTrust);
3100
3004
  while (candidate_it != candidate_blocks_by_work.end()) {
3101
3005
  if (!CBlockIndexWorkComparator()(candidate_it->second, invalid_walk_tip->pprev)) {
3102
3006
  setBlockIndexCandidates.insert(candidate_it->second);
@@ -3195,7 +3099,7 @@ void CChainState::ReceivedBlockTransactions(const CBlock& block, CBlockIndex* pi
3195
3099
  pindexNew->nDataPos = pos.nPos;
3196
3100
  pindexNew->nUndoPos = 0;
3197
3101
  pindexNew->nStatus |= BLOCK_HAVE_DATA;
3198
- if (DeploymentActiveAt(*pindexNew, m_params.GetConsensus(), Consensus::DEPLOYMENT_SEGWIT)) {
3102
+ if (pindexNew->pprev && IsBTC16BIPsEnabled(pindexNew->pprev->nTime)) {
3199
3103
  pindexNew->nStatus |= BLOCK_OPT_WITNESS;
3200
3104
  }
3201
3105
  pindexNew->RaiseValidity(BLOCK_VALID_TRANSACTIONS);
@@ -3239,7 +3143,7 @@ static bool CheckBlockHeader(const CBlockHeader& block, BlockValidationState& st
3239
3143
  return true;
3240
3144
  }
3241
3145
 
3242
- bool CheckBlock(const CBlock& block, BlockValidationState& state, const Consensus::Params& consensusParams, bool fCheckPOW, bool fCheckMerkleRoot)
3146
+ bool CheckBlock(const CBlock& block, BlockValidationState& state, const Consensus::Params& consensusParams, bool fCheckPOW, bool fCheckMerkleRoot, bool fCheckSignature)
3243
3147
  {
3244
3148
  // These are checks that are independent of context.
3245
3149
 
@@ -3248,7 +3152,7 @@ bool CheckBlock(const CBlock& block, BlockValidationState& state, const Consensu
3248
3152
 
3249
3153
  // Check that the header is valid (particularly PoW). This is mostly
3250
3154
  // redundant with the call in AcceptBlockHeader.
3251
- if (!CheckBlockHeader(block, state, consensusParams, fCheckPOW))
3155
+ if (!CheckBlockHeader(block, state, consensusParams, fCheckPOW && !block.IsProofOfStake()))
3252
3156
  return false;
3253
3157
 
3254
3158
  // Signet only: check block solution
@@ -3287,6 +3191,32 @@ bool CheckBlock(const CBlock& block, BlockValidationState& state, const Consensu
3287
3191
  if (block.vtx[i]->IsCoinBase())
3288
3192
  return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-cb-multiple", "more than one coinbase");
3289
3193
 
3194
+ // peercoin: only the second transaction can be the optional coinstake
3195
+ for (unsigned int i = 2; i < block.vtx.size(); i++)
3196
+ if (block.vtx[i]->IsCoinStake())
3197
+ return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-cs-missing", "coinstake in wrong position");
3198
+
3199
+ // peercoin: first coinbase output should be empty if proof-of-stake block
3200
+ if (block.IsProofOfStake() && !block.vtx[0]->vout[0].IsEmpty())
3201
+ return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-cb-notempty", "coinbase output not empty in PoS block");
3202
+
3203
+ // Check coinbase timestamp
3204
+ if (block.GetBlockTime() > (block.vtx[0]->nTime ? (int64_t)block.vtx[0]->nTime : block.GetBlockTime()) + (IsProtocolV09(block.GetBlockTime()) ? MAX_FUTURE_BLOCK_TIME : MAX_FUTURE_BLOCK_TIME_PREV9))
3205
+ return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-cb-time", "coinbase timestamp is too early");
3206
+
3207
+ // Check coinstake timestamp
3208
+ if (block.IsProofOfStake() && !CheckCoinStakeTimestamp(block.GetBlockTime(), block.vtx[1]->nTime ? (int64_t)block.vtx[1]->nTime : block.GetBlockTime()))
3209
+ return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-cs-time", "coinstake timestamp violation");
3210
+
3211
+ // Check coinbase reward
3212
+ CAmount nCoinbaseCost = 0;
3213
+ if (block.IsProofOfWork())
3214
+ nCoinbaseCost = (GetMinFee(*block.vtx[0], block.nTime) < PERKB_TX_FEE)? 0 : (GetMinFee(*block.vtx[0], block.nTime) - PERKB_TX_FEE);
3215
+ if (block.vtx[0]->GetValueOut() > (block.IsProofOfWork()? (GetProofOfWorkReward(block.nBits, block.GetBlockTime()) - nCoinbaseCost) : 0))
3216
+ return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-cb-amount",
3217
+ strprintf("CheckBlock() : coinbase reward exceeded %s > %s",
3218
+ FormatMoney(block.vtx[0]->GetValueOut()),
3219
+ FormatMoney(block.IsProofOfWork()? GetProofOfWorkReward(block.nBits, block.GetBlockTime()) : 0)));
3290
3220
  // Check transactions
3291
3221
  // Must check for duplicate inputs (see CVE-2018-17144)
3292
3222
  for (const auto& tx : block.vtx) {
@@ -3297,6 +3227,9 @@ bool CheckBlock(const CBlock& block, BlockValidationState& state, const Consensu
3297
3227
  assert(tx_state.GetResult() == TxValidationResult::TX_CONSENSUS);
3298
3228
  return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, tx_state.GetRejectReason(),
3299
3229
  strprintf("Transaction check failed (tx hash %s) %s", tx->GetHash().ToString(), tx_state.GetDebugMessage()));
3230
+ // peercoin: check transaction timestamp
3231
+ if (block.GetBlockTime() < (int64_t)tx->nTime)
3232
+ return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-tx-time", strprintf("%s : block timestamp earlier than transaction timestamp", __func__));
3300
3233
  }
3301
3234
  }
3302
3235
  unsigned int nSigOps = 0;
@@ -3310,6 +3243,12 @@ bool CheckBlock(const CBlock& block, BlockValidationState& state, const Consensu
3310
3243
  if (fCheckPOW && fCheckMerkleRoot)
3311
3244
  block.fChecked = true;
3312
3245
 
3246
+ // peercoin: check block signature
3247
+ // Only check block signature if check merkle root, c.f. commit 3cd01fdf
3248
+ // rfc6: validate signatures of proof of stake blocks only after 0.8 fork
3249
+ if (fCheckMerkleRoot && fCheckSignature && (block.IsProofOfStake() || !IsBTC16BIPsEnabled(block.GetBlockTime())) && !CheckBlockSignature(block))
3250
+ return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-blk-sign", strprintf("%s : bad block signature", __func__));
3251
+
3313
3252
  return true;
3314
3253
  }
3315
3254
 
@@ -3317,7 +3256,7 @@ void UpdateUncommittedBlockStructures(CBlock& block, const CBlockIndex* pindexPr
3317
3256
  {
3318
3257
  int commitpos = GetWitnessCommitmentIndex(block);
3319
3258
  static const std::vector<unsigned char> nonce(32, 0x00);
3320
- if (commitpos != NO_WITNESS_COMMITMENT && DeploymentActiveAfter(pindexPrev, consensusParams, Consensus::DEPLOYMENT_SEGWIT) && !block.vtx[0]->HasWitness()) {
3259
+ if (commitpos != NO_WITNESS_COMMITMENT && IsBTC16BIPsEnabled(pindexPrev->nTime) && !block.vtx[0]->HasWitness()) {
3321
3260
  CMutableTransaction tx(*block.vtx[0]);
3322
3261
  tx.vin[0].scriptWitness.stack.resize(1);
3323
3262
  tx.vin[0].scriptWitness.stack[0] = nonce;
@@ -3367,10 +3306,10 @@ static bool ContextualCheckBlockHeader(const CBlockHeader& block, BlockValidatio
3367
3306
  assert(pindexPrev != nullptr);
3368
3307
  const int nHeight = pindexPrev->nHeight + 1;
3369
3308
 
3370
- // Check proof of work
3309
+ // Check proof of work or proof-of-stake
3371
3310
  const Consensus::Params& consensusParams = params.GetConsensus();
3372
- if (block.nBits != GetNextWorkRequired(pindexPrev, &block, consensusParams))
3373
- return state.Invalid(BlockValidationResult::BLOCK_INVALID_HEADER, "bad-diffbits", "incorrect proof of work");
3311
+ if (block.nBits != GetNextTargetRequired(pindexPrev, block.nFlags & CBlockIndex::BLOCK_PROOF_OF_STAKE, consensusParams))
3312
+ return state.Invalid(BlockValidationResult::BLOCK_INVALID_HEADER, "bad-diffbits", "incorrect proof of work/stake");
3374
3313
 
3375
3314
  // Check against checkpoints
3376
3315
  if (fCheckpointsEnabled) {
@@ -3385,20 +3324,19 @@ static bool ContextualCheckBlockHeader(const CBlockHeader& block, BlockValidatio
3385
3324
  }
3386
3325
 
3387
3326
  // Check timestamp against prev
3388
- if (block.GetBlockTime() <= pindexPrev->GetMedianTimePast())
3327
+ if (block.GetBlockTime() <= pindexPrev->GetMedianTimePast() || block.GetBlockTime() + (IsProtocolV09(block.GetBlockTime()) ? MAX_FUTURE_BLOCK_TIME : MAX_FUTURE_BLOCK_TIME_PREV9) < pindexPrev->GetBlockTime())
3389
3328
  return state.Invalid(BlockValidationResult::BLOCK_INVALID_HEADER, "time-too-old", "block's timestamp is too early");
3390
3329
 
3391
3330
  // Check timestamp
3392
- if (block.GetBlockTime() > nAdjustedTime + MAX_FUTURE_BLOCK_TIME)
3331
+ if (block.GetBlockTime() > nAdjustedTime + (IsProtocolV09(block.GetBlockTime()) ? MAX_FUTURE_BLOCK_TIME : MAX_FUTURE_BLOCK_TIME_PREV9))
3393
3332
  return state.Invalid(BlockValidationResult::BLOCK_TIME_FUTURE, "time-too-new", "block timestamp too far in the future");
3394
3333
 
3395
- // Reject blocks with outdated version
3396
- if ((block.nVersion < 2 && DeploymentActiveAfter(pindexPrev, consensusParams, Consensus::DEPLOYMENT_HEIGHTINCB)) ||
3397
- (block.nVersion < 3 && DeploymentActiveAfter(pindexPrev, consensusParams, Consensus::DEPLOYMENT_DERSIG)) ||
3398
- (block.nVersion < 4 && DeploymentActiveAfter(pindexPrev, consensusParams, Consensus::DEPLOYMENT_CLTV))) {
3334
+ // Reject outdated version blocks when 95% (75% on testnet) of the network has upgraded:
3335
+ // check for version 2, 3 and 4 upgrades
3336
+ if ((block.nVersion < 2 && IsProtocolV06(pindexPrev)) ||
3337
+ (block.nVersion < 4 && IsProtocolV12(pindexPrev)))
3399
3338
  return state.Invalid(BlockValidationResult::BLOCK_INVALID_HEADER, strprintf("bad-version(0x%08x)", block.nVersion),
3400
3339
  strprintf("rejected nVersion=0x%08x block", block.nVersion));
3401
- }
3402
3340
 
3403
3341
  return true;
3404
3342
  }
@@ -3409,13 +3347,13 @@ static bool ContextualCheckBlockHeader(const CBlockHeader& block, BlockValidatio
3409
3347
  * in ConnectBlock().
3410
3348
  * Note that -reindex-chainstate skips the validation that happens here!
3411
3349
  */
3412
- static bool ContextualCheckBlock(const CBlock& block, BlockValidationState& state, const Consensus::Params& consensusParams, const CBlockIndex* pindexPrev)
3350
+ static bool ContextualCheckBlock(const CBlock& block, BlockValidationState& state, const CBlockIndex* pindexPrev)
3413
3351
  {
3414
3352
  const int nHeight = pindexPrev == nullptr ? 0 : pindexPrev->nHeight + 1;
3415
3353
 
3416
3354
  // Enforce BIP113 (Median Time Past).
3417
3355
  int nLockTimeFlags = 0;
3418
- if (DeploymentActiveAfter(pindexPrev, consensusParams, Consensus::DEPLOYMENT_CSV)) {
3356
+ if (pindexPrev && IsBTC16BIPsEnabled(pindexPrev->nTime)) {
3419
3357
  assert(pindexPrev != nullptr);
3420
3358
  nLockTimeFlags |= LOCKTIME_MEDIAN_TIME_PAST;
3421
3359
  }
@@ -3432,7 +3370,7 @@ static bool ContextualCheckBlock(const CBlock& block, BlockValidationState& stat
3432
3370
  }
3433
3371
 
3434
3372
  // Enforce rule that the coinbase starts with serialized block height
3435
- if (DeploymentActiveAfter(pindexPrev, consensusParams, Consensus::DEPLOYMENT_HEIGHTINCB))
3373
+ if (pindexPrev && IsProtocolV06(pindexPrev) && block.nVersion >= 2)
3436
3374
  {
3437
3375
  CScript expect = CScript() << nHeight;
3438
3376
  if (block.vtx[0]->vin[0].scriptSig.size() < expect.size() ||
@@ -3450,7 +3388,7 @@ static bool ContextualCheckBlock(const CBlock& block, BlockValidationState& stat
3450
3388
  // {0xaa, 0x21, 0xa9, 0xed}, and the following 32 bytes are SHA256^2(witness root, witness reserved value). In case there are
3451
3389
  // multiple, the last one is used.
3452
3390
  bool fHaveWitness = false;
3453
- if (DeploymentActiveAfter(pindexPrev, consensusParams, Consensus::DEPLOYMENT_SEGWIT)) {
3391
+ if (pindexPrev && IsBTC16BIPsEnabled(pindexPrev->nTime)) {
3454
3392
  int commitpos = GetWitnessCommitmentIndex(block);
3455
3393
  if (commitpos != NO_WITNESS_COMMITMENT) {
3456
3394
  bool malleated = false;
@@ -3510,7 +3448,7 @@ bool ChainstateManager::AcceptBlockHeader(const CBlockHeader& block, BlockValida
3510
3448
  return true;
3511
3449
  }
3512
3450
 
3513
- if (!CheckBlockHeader(block, state, chainparams.GetConsensus())) {
3451
+ if (!CheckBlockHeader(block, state, chainparams.GetConsensus(), !(block.nFlags & CBlockIndex::BLOCK_PROOF_OF_STAKE))) {
3514
3452
  LogPrint(BCLog::VALIDATION, "%s: Consensus::CheckBlockHeader: %s, %s\n", __func__, hash.ToString(), state.ToString());
3515
3453
  return false;
3516
3454
  }
@@ -3580,22 +3518,39 @@ bool ChainstateManager::AcceptBlockHeader(const CBlockHeader& block, BlockValida
3580
3518
  }
3581
3519
 
3582
3520
  // Exposed wrapper for AcceptBlockHeader
3583
- bool ChainstateManager::ProcessNewBlockHeaders(const std::vector<CBlockHeader>& headers, BlockValidationState& state, const CChainParams& chainparams, const CBlockIndex** ppindex)
3521
+ bool ChainstateManager::ProcessNewBlockHeaders(int32_t& nPoSTemperature, const uint256& lastAcceptedHeader, const std::vector<CBlockHeader>& headers, BlockValidationState& state, const CChainParams& chainparams, const CBlockIndex** ppindex)
3584
3522
  {
3585
3523
  AssertLockNotHeld(cs_main);
3586
3524
  {
3587
3525
  LOCK(cs_main);
3526
+
3527
+ int nCooling = POW_HEADER_COOLING;
3528
+ if (headers[0].hashPrevBlock != lastAcceptedHeader && !lastAcceptedHeader.IsNull()) {
3529
+ nPoSTemperature += (18 + headers.size()) / 10;
3530
+ nCooling = 0;
3531
+ }
3532
+
3588
3533
  for (const CBlockHeader& header : headers) {
3534
+ bool fPoS = header.nFlags & CBlockIndex::BLOCK_PROOF_OF_STAKE;
3535
+
3589
3536
  CBlockIndex *pindex = nullptr; // Use a temp pindex instead of ppindex to avoid a const_cast
3590
3537
  bool accepted{AcceptBlockHeader(header, state, chainparams, &pindex)};
3591
3538
  ActiveChainstate().CheckBlockIndex();
3592
3539
 
3593
3540
  if (!accepted) {
3541
+ nPoSTemperature += POW_HEADER_COOLING;
3594
3542
  return false;
3595
3543
  }
3596
3544
  if (ppindex) {
3597
3545
  *ppindex = pindex;
3598
3546
  }
3547
+
3548
+ if (fPoS) {
3549
+ nPoSTemperature++;
3550
+ } else { // PoW
3551
+ nPoSTemperature -= nCooling;
3552
+ nPoSTemperature = std::max((int)nPoSTemperature, 0);
3553
+ }
3599
3554
  }
3600
3555
  }
3601
3556
  if (NotifyHeaderTip(ActiveChainstate())) {
@@ -3613,6 +3568,7 @@ bool ChainstateManager::ProcessNewBlockHeaders(const std::vector<CBlockHeader>&
3613
3568
  bool CChainState::AcceptBlock(const std::shared_ptr<const CBlock>& pblock, BlockValidationState& state, CBlockIndex** ppindex, bool fRequested, const FlatFilePos* dbp, bool* fNewBlock)
3614
3569
  {
3615
3570
  const CBlock& block = *pblock;
3571
+ bool fCheckPoS = true;
3616
3572
 
3617
3573
  if (fNewBlock) *fNewBlock = false;
3618
3574
  AssertLockHeld(cs_main);
@@ -3626,11 +3582,17 @@ bool CChainState::AcceptBlock(const std::shared_ptr<const CBlock>& pblock, Block
3626
3582
  if (!accepted_header)
3627
3583
  return false;
3628
3584
 
3585
+ // peercoin: we should only accept blocks that can be connected to a prev block with validated PoS
3586
+ if (fCheckPoS && pindex->pprev && !pindex->pprev->IsValid(BLOCK_VALID_TRANSACTIONS)) {
3587
+ return error("%s: this block does not connect to any valid known block", __func__);
3588
+ }
3589
+
3629
3590
  // Try to process all requested blocks that we don't have, but only
3630
3591
  // process an unrequested block if it's new and has enough work to
3631
3592
  // advance our tip, and isn't too many blocks ahead.
3632
3593
  bool fAlreadyHave = pindex->nStatus & BLOCK_HAVE_DATA;
3633
- bool fHasMoreOrSameWork = (m_chain.Tip() ? pindex->nChainWork >= m_chain.Tip()->nChainWork : true);
3594
+ bool fHasMoreOrSameWork = (m_chain.Tip() ? pindex->nChainTrust >= m_chain.Tip()->nChainTrust : true);
3595
+
3634
3596
  // Blocks that are too out-of-order needlessly limit the effectiveness of
3635
3597
  // pruning, because pruning will not delete block files that contain any
3636
3598
  // blocks which are too close in height to the tip. Apply this test
@@ -3656,11 +3618,11 @@ bool CChainState::AcceptBlock(const std::shared_ptr<const CBlock>& pblock, Block
3656
3618
  // If our tip is behind, a peer could try to send us
3657
3619
  // low-work blocks on a fake chain that we would never
3658
3620
  // request; don't process these.
3659
- if (pindex->nChainWork < nMinimumChainWork) return true;
3621
+ if (pindex->nChainTrust < nMinimumChainWork) return true;
3660
3622
  }
3661
3623
 
3662
3624
  if (!CheckBlock(block, state, m_params.GetConsensus()) ||
3663
- !ContextualCheckBlock(block, state, m_params.GetConsensus(), pindex->pprev)) {
3625
+ !ContextualCheckBlock(block, state, pindex->pprev)) {
3664
3626
  if (state.IsInvalid() && state.GetResult() != BlockValidationResult::BLOCK_MUTATED) {
3665
3627
  pindex->nStatus |= BLOCK_FAILED_VALID;
3666
3628
  m_blockman.m_dirty_blockindex.insert(pindex);
@@ -3668,9 +3630,16 @@ bool CChainState::AcceptBlock(const std::shared_ptr<const CBlock>& pblock, Block
3668
3630
  return error("%s: %s", __func__, state.ToString());
3669
3631
  }
3670
3632
 
3633
+ // peercoin: check PoS
3634
+ if (fCheckPoS && !PeercoinContextualBlockChecks(block, state, pindex, false, m_chainman.ActiveChainstate())) {
3635
+ pindex->nStatus |= BLOCK_FAILED_VALID;
3636
+ m_blockman.m_dirty_blockindex.insert(pindex);
3637
+ return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-pos", "proof of stake is incorrect");
3638
+ }
3639
+
3671
3640
  // Header is valid/has work, merkle tree and segwit merkle tree are good...RELAY NOW
3672
3641
  // (but if it does not build on our best tip, let the SendMessages loop relay it)
3673
- if (!IsInitialBlockDownload() && m_chain.Tip() == pindex->pprev)
3642
+ if (!m_chainman.ActiveChainstate().IsInitialBlockDownload() && m_chain.Tip() == pindex->pprev)
3674
3643
  GetMainSignals().NewPoWValidBlock(pindex, pblock);
3675
3644
 
3676
3645
  // Write block to history file
@@ -3687,19 +3656,19 @@ bool CChainState::AcceptBlock(const std::shared_ptr<const CBlock>& pblock, Block
3687
3656
  }
3688
3657
 
3689
3658
  FlushStateToDisk(state, FlushStateMode::NONE);
3690
-
3691
3659
  CheckBlockIndex();
3692
3660
 
3693
3661
  return true;
3694
3662
  }
3695
3663
 
3696
- bool ChainstateManager::ProcessNewBlock(const CChainParams& chainparams, const std::shared_ptr<const CBlock>& block, bool force_processing, bool* new_block)
3664
+ bool ChainstateManager::ProcessNewBlock(const CChainParams& chainparams, const std::shared_ptr<const CBlock>& block, bool force_processing, bool* new_block, CBlockIndex** ppindex, bool* fPoSDuplicate)
3697
3665
  {
3698
3666
  AssertLockNotHeld(cs_main);
3699
3667
 
3700
3668
  {
3701
3669
  CBlockIndex *pindex = nullptr;
3702
3670
  if (new_block) *new_block = false;
3671
+ if (fPoSDuplicate) *fPoSDuplicate = false;
3703
3672
  BlockValidationState state;
3704
3673
 
3705
3674
  // CheckBlock() does not support multi-threaded block validation because CBlock::fChecked can cause data race.
@@ -3716,10 +3685,19 @@ bool ChainstateManager::ProcessNewBlock(const CChainParams& chainparams, const s
3716
3685
  // Store to disk
3717
3686
  ret = ActiveChainstate().AcceptBlock(block, state, &pindex, force_processing, nullptr, new_block);
3718
3687
  }
3688
+ if (ppindex)
3689
+ *ppindex = ret ? pindex : nullptr;
3719
3690
  if (!ret) {
3720
3691
  GetMainSignals().BlockChecked(*block, state);
3721
3692
  return error("%s: AcceptBlock FAILED (%s)", __func__, state.ToString());
3722
3693
  }
3694
+
3695
+ if (pindex->IsProofOfStake() && !ActiveChainstate().IsInitialBlockDownload()) {
3696
+ int32_t ndx = univHash(pindex->hashProofOfStake);
3697
+ if (fPoSDuplicate && vStakeSeen[ndx] == pindex->hashProofOfStake)
3698
+ *fPoSDuplicate = true;
3699
+ vStakeSeen[ndx] = pindex->hashProofOfStake;
3700
+ }
3723
3701
  }
3724
3702
 
3725
3703
  NotifyHeaderTip(ActiveChainstate());
@@ -3768,7 +3746,7 @@ bool TestBlockValidity(BlockValidationState& state,
3768
3746
  return error("%s: Consensus::ContextualCheckBlockHeader: %s", __func__, state.ToString());
3769
3747
  if (!CheckBlock(block, state, chainparams.GetConsensus(), fCheckPOW, fCheckMerkleRoot))
3770
3748
  return error("%s: Consensus::CheckBlock: %s", __func__, state.ToString());
3771
- if (!ContextualCheckBlock(block, state, chainparams.GetConsensus(), pindexPrev))
3749
+ if (!ContextualCheckBlock(block, state, pindexPrev))
3772
3750
  return error("%s: Consensus::ContextualCheckBlock: %s", __func__, state.ToString());
3773
3751
  if (!chainstate.ConnectBlock(block, state, &indexDummy, viewNew, true)) {
3774
3752
  return false;
@@ -3778,16 +3756,6 @@ bool TestBlockValidity(BlockValidationState& state,
3778
3756
  return true;
3779
3757
  }
3780
3758
 
3781
- /* This function is called from the RPC code for pruneblockchain */
3782
- void PruneBlockFilesManual(CChainState& active_chainstate, int nManualPruneHeight)
3783
- {
3784
- BlockValidationState state;
3785
- if (!active_chainstate.FlushStateToDisk(
3786
- state, FlushStateMode::NONE, nManualPruneHeight)) {
3787
- LogPrintf("%s: failed to flush state (%s)\n", __func__, state.ToString());
3788
- }
3789
- }
3790
-
3791
3759
  void CChainState::LoadMempool(const ArgsManager& args)
3792
3760
  {
3793
3761
  if (!m_mempool) return;
@@ -3874,10 +3842,10 @@ bool CVerifyDB::VerifyDB(
3874
3842
  if (pindex->nHeight <= chainstate.m_chain.Height() - nCheckDepth) {
3875
3843
  break;
3876
3844
  }
3877
- if ((fPruneMode || is_snapshot_cs) && !(pindex->nStatus & BLOCK_HAVE_DATA)) {
3878
- // If pruning or running under an assumeutxo snapshot, only go
3845
+ if (is_snapshot_cs && !(pindex->nStatus & BLOCK_HAVE_DATA)) {
3846
+ // If running under an assumeutxo snapshot, only go
3879
3847
  // back as far as we have data.
3880
- LogPrintf("VerifyDB(): block verification stopping at height %d (pruning, no data)\n", pindex->nHeight);
3848
+ LogPrintf("VerifyDB(): block verification stopping at height %d (no data)\n", pindex->nHeight);
3881
3849
  break;
3882
3850
  }
3883
3851
  CBlock block;
@@ -3968,7 +3936,7 @@ bool CChainState::RollforwardBlock(const CBlockIndex* pindex, CCoinsViewCache& i
3968
3936
  }
3969
3937
  }
3970
3938
  // Pass check = true as every addition may be an overwrite.
3971
- AddCoins(inputs, *tx, pindex->nHeight, true);
3939
+ AddCoins(inputs, *tx, pindex->nHeight, true, IsProtocolV12(pindex));
3972
3940
  }
3973
3941
  return true;
3974
3942
  }
@@ -4047,7 +4015,7 @@ bool CChainState::NeedsRedownload() const
4047
4015
  // At and above m_params.SegwitHeight, segwit consensus rules must be validated
4048
4016
  CBlockIndex* block{m_chain.Tip()};
4049
4017
 
4050
- while (block != nullptr && DeploymentActiveAt(*block, m_params.GetConsensus(), Consensus::DEPLOYMENT_SEGWIT)) {
4018
+ while (block != nullptr && block->pprev && IsBTC16BIPsEnabled(block->pprev->nTime)) {
4051
4019
  if (!(block->nStatus & BLOCK_OPT_WITNESS)) {
4052
4020
  // block is insufficiently validated for a segwit client
4053
4021
  return true;
@@ -4074,11 +4042,6 @@ void UnloadBlockIndex(CTxMemPool* mempool, ChainstateManager& chainman)
4074
4042
  chainman.Unload();
4075
4043
  pindexBestHeader = nullptr;
4076
4044
  if (mempool) mempool->clear();
4077
- g_versionbitscache.Clear();
4078
- for (int b = 0; b < VERSIONBITS_NUM_BITS; b++) {
4079
- warningcache[b].clear();
4080
- }
4081
- fHavePruned = false;
4082
4045
  }
4083
4046
 
4084
4047
  bool ChainstateManager::LoadBlockIndex()
@@ -4330,16 +4293,8 @@ void CChainState::CheckBlockIndex()
4330
4293
  if (!pindex->HaveTxsDownloaded()) assert(pindex->nSequenceId <= 0); // nSequenceId can't be set positive for blocks that aren't linked (negative is used for preciousblock)
4331
4294
  // VALID_TRANSACTIONS is equivalent to nTx > 0 for all nodes (whether or not pruning has occurred).
4332
4295
  // HAVE_DATA is only equivalent to nTx > 0 (or VALID_TRANSACTIONS) if no pruning has occurred.
4333
- // Unless these indexes are assumed valid and pending block download on a
4334
- // background chainstate.
4335
- if (!fHavePruned && !pindex->IsAssumedValid()) {
4336
- // If we've never pruned, then HAVE_DATA should be equivalent to nTx > 0
4337
- assert(!(pindex->nStatus & BLOCK_HAVE_DATA) == (pindex->nTx == 0));
4338
- assert(pindexFirstMissing == pindexFirstNeverProcessed);
4339
- } else {
4340
- // If we have pruned, then we can only say that HAVE_DATA implies nTx > 0
4341
- if (pindex->nStatus & BLOCK_HAVE_DATA) assert(pindex->nTx > 0);
4342
- }
4296
+ assert(!(pindex->nStatus & BLOCK_HAVE_DATA) == (pindex->nTx == 0));
4297
+ assert(pindexFirstMissing == pindexFirstNeverProcessed);
4343
4298
  if (pindex->nStatus & BLOCK_HAVE_UNDO) assert(pindex->nStatus & BLOCK_HAVE_DATA);
4344
4299
  if (pindex->IsAssumedValid()) {
4345
4300
  // Assumed-valid blocks should have some nTx value.
@@ -4355,7 +4310,7 @@ void CChainState::CheckBlockIndex()
4355
4310
  assert((pindexFirstNeverProcessed == nullptr) == pindex->HaveTxsDownloaded());
4356
4311
  assert((pindexFirstNotTransactionsValid == nullptr) == pindex->HaveTxsDownloaded());
4357
4312
  assert(pindex->nHeight == nHeight); // nHeight must be consistent.
4358
- assert(pindex->pprev == nullptr || pindex->nChainWork >= pindex->pprev->nChainWork); // For every block except the genesis block, the chainwork must be larger than the parent's.
4313
+ assert(pindex->pprev == nullptr || pindex->nChainTrust >= pindex->pprev->nChainTrust); // For every block except the genesis block, the chainwork must be larger than the parent's.
4359
4314
  assert(nHeight < 2 || (pindex->pskip && (pindex->pskip->nHeight < nHeight))); // The pskip pointer must point back for all but the first 2 blocks.
4360
4315
  assert(pindexFirstNotTreeValid == nullptr); // All m_blockman.m_block_index entries must at least be TREE valid
4361
4316
  if ((pindex->nStatus & BLOCK_VALID_MASK) >= BLOCK_VALID_TREE) assert(pindexFirstNotTreeValid == nullptr); // TREE valid implies all parents are TREE valid
@@ -4371,8 +4326,7 @@ void CChainState::CheckBlockIndex()
4371
4326
 
4372
4327
  // If this block sorts at least as good as the current tip and
4373
4328
  // is valid and we have all data for its parents, it must be in
4374
- // setBlockIndexCandidates. m_chain.Tip() must also be there
4375
- // even if some data has been pruned.
4329
+ // setBlockIndexCandidates. m_chain.Tip() must also be there.
4376
4330
  //
4377
4331
  // Don't perform this check for the background chainstate since
4378
4332
  // its setBlockIndexCandidates shouldn't have some entries (i.e. those past the
@@ -4404,23 +4358,6 @@ void CChainState::CheckBlockIndex()
4404
4358
  }
4405
4359
  if (!(pindex->nStatus & BLOCK_HAVE_DATA)) assert(!foundInUnlinked); // Can't be in m_blocks_unlinked if we don't HAVE_DATA
4406
4360
  if (pindexFirstMissing == nullptr) assert(!foundInUnlinked); // We aren't missing data for any parent -- cannot be in m_blocks_unlinked.
4407
- if (pindex->pprev && (pindex->nStatus & BLOCK_HAVE_DATA) && pindexFirstNeverProcessed == nullptr && pindexFirstMissing != nullptr) {
4408
- // We HAVE_DATA for this block, have received data for all parents at some point, but we're currently missing data for some parent.
4409
- assert(fHavePruned); // We must have pruned.
4410
- // This block may have entered m_blocks_unlinked if:
4411
- // - it has a descendant that at some point had more work than the
4412
- // tip, and
4413
- // - we tried switching to that descendant but were missing
4414
- // data for some intermediate block between m_chain and the
4415
- // tip.
4416
- // So if this block is itself better than m_chain.Tip() and it wasn't in
4417
- // setBlockIndexCandidates, then it must be in m_blocks_unlinked.
4418
- if (!CBlockIndexWorkComparator()(pindex, m_chain.Tip()) && setBlockIndexCandidates.count(pindex) == 0) {
4419
- if (pindexFirstInvalid == nullptr) {
4420
- assert(foundInUnlinked);
4421
- }
4422
- }
4423
- }
4424
4361
  // assert(pindex->GetBlockHash() == pindex->GetBlockHeader().GetHash()); // Perhaps too slow
4425
4362
  // End: actual consistency checks.
4426
4363
 
@@ -4678,6 +4615,126 @@ double GuessVerificationProgress(const ChainTxData& data, const CBlockIndex *pin
4678
4615
  return std::min<double>(pindex->nChainTx / fTxTotal, 1.0);
4679
4616
  }
4680
4617
 
4618
+
4619
+
4620
+
4621
+
4622
+ // peercoin: total coin age spent in transaction, in the unit of coin-days.
4623
+ // Only those coins meeting minimum age requirement counts. As those
4624
+ // transactions not in main chain are not currently indexed so we
4625
+ // might not find out about their coin age. Older transactions are
4626
+ // guaranteed to be in main chain by sync-checkpoint. This rule is
4627
+ // introduced to help nodes establish a consistent view of the coin
4628
+ // age (trust score) of competing branches.
4629
+ bool GetCoinAge(const CTransaction& tx, const CCoinsViewCache &view, uint64_t& nCoinAge, unsigned int nTimeTx, bool isTrueCoinAge)
4630
+ {
4631
+ arith_uint256 bnCentSecond = 0; // coin age in the unit of cent-seconds
4632
+ nCoinAge = 0;
4633
+
4634
+ if (tx.IsCoinBase())
4635
+ return true;
4636
+
4637
+ // Transaction index is required to get to block header
4638
+ if (!g_txindex)
4639
+ return false; // Transaction index not available
4640
+
4641
+ for (const auto& txin : tx.vin)
4642
+ {
4643
+ // First try finding the previous transaction in database
4644
+ const COutPoint &prevout = txin.prevout;
4645
+ Coin coin;
4646
+
4647
+ if (isTrueCoinAge && !view.GetCoin(prevout, coin))
4648
+ continue; // previous transaction not in main chain
4649
+ if (nTimeTx < coin.nTime)
4650
+ return false; // Transaction timestamp violation
4651
+
4652
+ CDiskTxPos postx;
4653
+ CBlockHeader header;
4654
+ CTransactionRef txPrev;
4655
+ auto it = g_txindex->cachedTxs.find(prevout.hash);
4656
+ if (it != g_txindex->cachedTxs.end()) {
4657
+ header = it->second.first;
4658
+ txPrev = it->second.second;
4659
+ } else {
4660
+ if (g_txindex->FindTxPosition(prevout.hash, postx)) {
4661
+ CAutoFile file(OpenBlockFile(postx, true), SER_DISK, CLIENT_VERSION);
4662
+ try {
4663
+ file >> header;
4664
+ fseek(file.Get(), postx.nTxOffset, SEEK_CUR);
4665
+ file >> txPrev;
4666
+ } catch (std::exception &e) {
4667
+ return error("%s() : deserialize or I/O error in GetCoinAge()", __PRETTY_FUNCTION__);
4668
+ }
4669
+ } else
4670
+ return error("%s() : tx missing in tx index in GetCoinAge()", __PRETTY_FUNCTION__);
4671
+ g_txindex->cachedTxs[prevout.hash] = std::pair(header,txPrev);
4672
+ }
4673
+
4674
+ if (txPrev->GetHash() != prevout.hash)
4675
+ return error("%s() : txid mismatch in GetCoinAge()", __PRETTY_FUNCTION__);
4676
+
4677
+ if (header.GetBlockTime() + Params().GetConsensus().nStakeMinAge > nTimeTx)
4678
+ continue; // only count coins meeting min age requirement
4679
+
4680
+ int64_t nValueIn = txPrev->vout[txin.prevout.n].nValue;
4681
+ int nEffectiveAge = nTimeTx-(txPrev->nTime ? txPrev->nTime : header.GetBlockTime());
4682
+
4683
+ if (!isTrueCoinAge || IsProtocolV09(nTimeTx))
4684
+ nEffectiveAge = std::min(nEffectiveAge, 365 * 24 * 60 * 60);
4685
+
4686
+ bnCentSecond += arith_uint256(nValueIn) * nEffectiveAge / CENT;
4687
+
4688
+ if (gArgs.GetBoolArg("-printcoinage", false))
4689
+ LogPrintf("coin age nValueIn=%-12lld nTimeDiff=%d bnCentSecond=%s\n", nValueIn, nEffectiveAge, bnCentSecond.ToString());
4690
+ }
4691
+
4692
+ arith_uint256 bnCoinDay = bnCentSecond * CENT / COIN / (24 * 60 * 60);
4693
+ if (gArgs.GetBoolArg("-printcoinage", false))
4694
+ LogPrintf("coin age bnCoinDay=%s\n", bnCoinDay.ToString());
4695
+ nCoinAge = bnCoinDay.GetLow64();
4696
+ return true;
4697
+ }
4698
+
4699
+ // peercoin: sign block
4700
+ typedef std::vector<unsigned char> valtype;
4701
+ bool SignBlock(CBlock& block, const CWallet& keystore)
4702
+ {
4703
+ std::vector<valtype> vSolutions;
4704
+ const CTxOut& txout = block.IsProofOfStake()? block.vtx[1]->vout[1] : block.vtx[0]->vout[0];
4705
+
4706
+ if (Solver(txout.scriptPubKey, vSolutions) != TxoutType::PUBKEY)
4707
+ return false;
4708
+
4709
+ // Sign
4710
+ const valtype& vchPubKey = vSolutions[0];
4711
+ CKey key;
4712
+ if (!keystore.GetLegacyScriptPubKeyMan()->GetKey(CKeyID(Hash160(vchPubKey)), key))
4713
+ return false;
4714
+ if (key.GetPubKey() != CPubKey(vchPubKey))
4715
+ return false;
4716
+ return key.Sign(block.GetHash(), block.vchBlockSig, 0);
4717
+ }
4718
+
4719
+ // peercoin: check block signature
4720
+ bool CheckBlockSignature(const CBlock& block)
4721
+ {
4722
+ if (block.GetHash() == Params().GetConsensus().hashGenesisBlock)
4723
+ return block.vchBlockSig.empty();
4724
+
4725
+ std::vector<valtype> vSolutions;
4726
+ const CTxOut& txout = block.IsProofOfStake()? block.vtx[1]->vout[1] : block.vtx[0]->vout[0];
4727
+
4728
+ if (Solver(txout.scriptPubKey, vSolutions) != TxoutType::PUBKEY)
4729
+ return false;
4730
+
4731
+ const valtype& vchPubKey = vSolutions[0];
4732
+ CPubKey key(vchPubKey);
4733
+ if (block.vchBlockSig.empty())
4734
+ return false;
4735
+ return key.Verify(block.GetHash(), block.vchBlockSig);
4736
+ }
4737
+
4681
4738
  std::optional<uint256> ChainstateManager::SnapshotBlockhash() const
4682
4739
  {
4683
4740
  LOCK(::cs_main);
@@ -5009,7 +5066,7 @@ bool ChainstateManager::PopulateAndValidateSnapshot(
5009
5066
 
5010
5067
  // Fake BLOCK_OPT_WITNESS so that CChainState::NeedsRedownload()
5011
5068
  // won't ask to rewind the entire assumed-valid chain on startup.
5012
- if (DeploymentActiveAt(*index, ::Params().GetConsensus(), Consensus::DEPLOYMENT_SEGWIT)) {
5069
+ if (IsBTC16BIPsEnabled(index->nTime)) {
5013
5070
  index->nStatus |= BLOCK_OPT_WITNESS;
5014
5071
  }
5015
5072
 
src/validation.h CHANGED
@@ -16,16 +16,17 @@
16
16
  #include <consensus/amount.h>
17
17
  #include <fs.h>
18
18
  #include <node/blockstorage.h>
19
- #include <policy/feerate.h>
20
19
  #include <policy/packages.h>
21
20
  #include <script/script_error.h>
22
21
  #include <sync.h>
22
+ #include <chain.h>
23
23
  #include <txdb.h>
24
24
  #include <txmempool.h> // For CTxMemPool::cs
25
25
  #include <uint256.h>
26
26
  #include <util/check.h>
27
27
  #include <util/hasher.h>
28
28
  #include <util/translation.h>
29
+ #include <wallet/wallet.h>
29
30
 
30
31
  #include <atomic>
31
32
  #include <map>
@@ -41,8 +42,14 @@
41
42
  class CChainState;
42
43
  class CBlockTreeDB;
43
44
  class CChainParams;
45
+ namespace wallet {
46
+ class CWallet;
47
+ } // namespace wallet
48
+ //class CWallet;
49
+ using wallet::CWallet;
44
50
  class CTxMemPool;
45
51
  class ChainstateManager;
52
+ class CKeyStore;
46
53
  struct ChainTxData;
47
54
  struct DisconnectedBlockTransactions;
48
55
  struct PrecomputedTransactionData;
@@ -52,8 +59,6 @@ namespace node {
52
59
  class SnapshotMetadata;
53
60
  } // namespace node
54
61
 
55
- /** Default for -minrelaytxfee, minimum relay fee for transactions */
56
- static const unsigned int DEFAULT_MIN_RELAY_TX_FEE = 1000;
57
62
  /** Default for -limitancestorcount, max number of in-mempool ancestors */
58
63
  static const unsigned int DEFAULT_ANCESTOR_LIMIT = 25;
59
64
  /** Default for -limitancestorsize, maximum kilobytes of tx + all in-mempool ancestors */
@@ -80,7 +85,7 @@ static const int MAX_SCRIPTCHECK_THREADS = 15;
80
85
  static const int DEFAULT_SCRIPTCHECK_THREADS = 0;
81
86
  static const int64_t DEFAULT_MAX_TIP_AGE = 24 * 60 * 60;
82
87
  static const bool DEFAULT_CHECKPOINTS_ENABLED = true;
83
- static const bool DEFAULT_TXINDEX = false;
88
+ static const bool DEFAULT_TXINDEX = true; // peercoin: txindex is required for PoS calculations (might change in the future)
84
89
  static constexpr bool DEFAULT_COINSTATSINDEX{false};
85
90
  static const char* const DEFAULT_BLOCKFILTERINDEX = "0";
86
91
  /** Default for -persistmempool */
@@ -120,8 +125,7 @@ extern bool g_parallel_script_checks;
120
125
  extern bool fRequireStandard;
121
126
  extern bool fCheckBlockIndex;
122
127
  extern bool fCheckpointsEnabled;
123
- /** A fee rate smaller than this is considered zero fee (for relaying, mining and transaction creation) */
124
- extern CFeeRate minRelayTxFee;
128
+ extern bool fAlerts;
125
129
  /** If the tip is older than this (in seconds), the node is considered to be in initial block download. */
126
130
  extern int64_t nMaxTipAge;
127
131
 
@@ -134,9 +138,11 @@ extern arith_uint256 nMinimumChainWork;
134
138
  /** Best header we've seen so far (used for getheaders queries' starting points). */
135
139
  extern CBlockIndex *pindexBestHeader;
136
140
 
141
+
137
142
  /** Documentation for argument 'checklevel'. */
138
143
  extern const std::vector<std::string> CHECKLEVEL_DOC;
139
144
 
145
+
140
146
  /** Unload database information */
141
147
  void UnloadBlockIndex(CTxMemPool* mempool, ChainstateManager& chainman);
142
148
  /** Run instances of script checking worker threads */
@@ -144,15 +150,12 @@ void StartScriptCheckWorkerThreads(int threads_num);
144
150
  /** Stop all of the script checking worker threads */
145
151
  void StopScriptCheckWorkerThreads();
146
152
 
147
- CAmount GetBlockSubsidy(int nHeight, const Consensus::Params& consensusParams);
148
153
 
149
154
  bool AbortNode(BlockValidationState& state, const std::string& strMessage, const bilingual_str& userMessage = bilingual_str{});
150
155
 
151
156
  /** Guess verification progress (as a fraction between 0.0=genesis and 1.0=current tip). */
152
157
  double GuessVerificationProgress(const ChainTxData& data, const CBlockIndex* pindex);
153
158
 
154
- /** Prune block files up to a given height */
155
- void PruneBlockFilesManual(CChainState& active_chainstate, int nManualPruneHeight);
156
159
 
157
160
  /**
158
161
  * Validation result for a single transaction mempool acceptance.
@@ -272,7 +275,6 @@ MempoolAcceptResult AcceptToMemoryPool(CChainState& active_chainstate, const CTr
272
275
  PackageMempoolAcceptResult ProcessNewPackage(CChainState& active_chainstate, CTxMemPool& pool,
273
276
  const Package& txns, bool test_accept)
274
277
  EXCLUSIVE_LOCKS_REQUIRED(cs_main);
275
-
276
278
  /** Transaction validation functions */
277
279
 
278
280
  /**
@@ -351,7 +353,7 @@ void InitScriptExecutionCache();
351
353
  /** Functions for validating blocks and updating the block tree */
352
354
 
353
355
  /** Context-independent validity checks */
354
- bool CheckBlock(const CBlock& block, BlockValidationState& state, const Consensus::Params& consensusParams, bool fCheckPOW = true, bool fCheckMerkleRoot = true);
356
+ bool CheckBlock(const CBlock& block, BlockValidationState& state, const Consensus::Params& consensusParams, bool fCheckPOW = true, bool fCheckMerkleRoot = true, bool fCheckSignature = true);
355
357
 
356
358
  /** Check a block is completely valid from start to finish (only works on top of our current best block) */
357
359
  bool TestBlockValidity(BlockValidationState& state,
@@ -624,10 +626,6 @@ public:
624
626
  //! Unconditionally flush all changes to disk.
625
627
  void ForceFlushStateToDisk();
626
628
 
627
- //! Prune blockfiles from the disk if necessary and then flush chainstate changes
628
- //! if we pruned.
629
- void PruneAndFlush();
630
-
631
629
  /**
632
630
  * Find the best known block, and make it the tip of the block chain. The
633
631
  * result is either failure or an activated best chain. pblock is either
@@ -961,7 +959,7 @@ public:
961
959
  * @param[out] new_block A boolean which is set to indicate if the block was first received via this call
962
960
  * @returns If the block was processed, independently of block validity
963
961
  */
964
- bool ProcessNewBlock(const CChainParams& chainparams, const std::shared_ptr<const CBlock>& block, bool force_processing, bool* new_block) LOCKS_EXCLUDED(cs_main);
962
+ bool ProcessNewBlock(const CChainParams& chainparams, const std::shared_ptr<const CBlock>& block, bool force_processing, bool* new_block, CBlockIndex** ppindex = nullptr, bool* fPoSDuplicate = nullptr) LOCKS_EXCLUDED(cs_main);
965
963
 
966
964
  /**
967
965
  * Process incoming block headers.
@@ -974,7 +972,7 @@ public:
974
972
  * @param[in] chainparams The params for the chain we want to connect to
975
973
  * @param[out] ppindex If set, the pointer will be set to point to the last new block index object for the given headers
976
974
  */
977
- bool ProcessNewBlockHeaders(const std::vector<CBlockHeader>& block, BlockValidationState& state, const CChainParams& chainparams, const CBlockIndex** ppindex = nullptr) LOCKS_EXCLUDED(cs_main);
975
+ bool ProcessNewBlockHeaders(int32_t& nPoSTemperature, const uint256& lastAcceptedHeader, const std::vector<CBlockHeader>& block, BlockValidationState& state, const CChainParams& chainparams, const CBlockIndex** ppindex = nullptr) LOCKS_EXCLUDED(cs_main);
978
976
 
979
977
  /**
980
978
  * Try to add a transaction to the memory pool.
@@ -1013,6 +1011,12 @@ bool DumpMempool(const CTxMemPool& pool, FopenFn mockable_fopen_function = fsbri
1013
1011
  /** Load the mempool from disk. */
1014
1012
  bool LoadMempool(CTxMemPool& pool, CChainState& active_chainstate, FopenFn mockable_fopen_function = fsbridge::fopen);
1015
1013
 
1014
+ // peercoin:
1015
+ CAmount GetProofOfWorkReward(unsigned int nBits, uint32_t nTime);
1016
+ CAmount GetProofOfStakeReward(int64_t nCoinAge, uint32_t nTime, uint64_t nMoneySupply);
1017
+ bool GetCoinAge(const CTransaction& tx, const CCoinsViewCache &view, uint64_t& nCoinAge, unsigned int nTimeTx, bool isTrueCoinAge = true); // peercoin: get transaction coin age
1018
+ bool SignBlock(CBlock& block, const CWallet& keystore);
1019
+ bool CheckBlockSignature(const CBlock& block);
1016
1020
  /**
1017
1021
  * Return the expected assumeutxo value for a given height, if one exists.
1018
1022
  *
src/validationinterface.h CHANGED
@@ -109,7 +109,6 @@ protected:
109
109
  * - SIZELIMIT (removed in size limiting if the mempool exceeds -maxmempool megabytes)
110
110
  * - REORG (removed during a reorg)
111
111
  * - CONFLICT (removed because it conflicts with in-block transaction)
112
- * - REPLACED (removed due to RBF replacement)
113
112
  *
114
113
  * This does not fire for transactions that are removed from the mempool
115
114
  * because they have been included in a block. Any client that is interested
src/version.h CHANGED
@@ -9,13 +9,14 @@
9
9
  * network protocol versioning
10
10
  */
11
11
 
12
- static const int PROTOCOL_VERSION = 70016;
12
+ static const int PROTOCOL_VERSION = 70017;
13
+ static const int OLD_VERSION = 70014; // peercoin: used to communicate with clients that don't know how to send PoS information in headers
13
14
 
14
15
  //! initial proto version, to be increased after version/verack negotiation
15
16
  static const int INIT_PROTO_VERSION = 209;
16
17
 
17
18
  //! disconnect from peers older than this proto version
18
- static const int MIN_PEER_PROTO_VERSION = 31800;
19
+ static const int MIN_PEER_PROTO_VERSION = 70016;
19
20
 
20
21
  //! BIP 0031, pong message, is enabled for all versions AFTER this one
21
22
  static const int BIP0031_VERSION = 60000;
src/versionbits.cpp DELETED
@@ -1,246 +0,0 @@
1
- // Copyright (c) 2016-2021 The Bitcoin Core developers
2
- // Distributed under the MIT software license, see the accompanying
3
- // file COPYING or http://www.opensource.org/licenses/mit-license.php.
4
-
5
- #include <versionbits.h>
6
- #include <consensus/params.h>
7
-
8
- ThresholdState AbstractThresholdConditionChecker::GetStateFor(const CBlockIndex* pindexPrev, const Consensus::Params& params, ThresholdConditionCache& cache) const
9
- {
10
- int nPeriod = Period(params);
11
- int nThreshold = Threshold(params);
12
- int min_activation_height = MinActivationHeight(params);
13
- int64_t nTimeStart = BeginTime(params);
14
- int64_t nTimeTimeout = EndTime(params);
15
-
16
- // Check if this deployment is always active.
17
- if (nTimeStart == Consensus::BIP9Deployment::ALWAYS_ACTIVE) {
18
- return ThresholdState::ACTIVE;
19
- }
20
-
21
- // Check if this deployment is never active.
22
- if (nTimeStart == Consensus::BIP9Deployment::NEVER_ACTIVE) {
23
- return ThresholdState::FAILED;
24
- }
25
-
26
- // A block's state is always the same as that of the first of its period, so it is computed based on a pindexPrev whose height equals a multiple of nPeriod - 1.
27
- if (pindexPrev != nullptr) {
28
- pindexPrev = pindexPrev->GetAncestor(pindexPrev->nHeight - ((pindexPrev->nHeight + 1) % nPeriod));
29
- }
30
-
31
- // Walk backwards in steps of nPeriod to find a pindexPrev whose information is known
32
- std::vector<const CBlockIndex*> vToCompute;
33
- while (cache.count(pindexPrev) == 0) {
34
- if (pindexPrev == nullptr) {
35
- // The genesis block is by definition defined.
36
- cache[pindexPrev] = ThresholdState::DEFINED;
37
- break;
38
- }
39
- if (pindexPrev->GetMedianTimePast() < nTimeStart) {
40
- // Optimization: don't recompute down further, as we know every earlier block will be before the start time
41
- cache[pindexPrev] = ThresholdState::DEFINED;
42
- break;
43
- }
44
- vToCompute.push_back(pindexPrev);
45
- pindexPrev = pindexPrev->GetAncestor(pindexPrev->nHeight - nPeriod);
46
- }
47
-
48
- // At this point, cache[pindexPrev] is known
49
- assert(cache.count(pindexPrev));
50
- ThresholdState state = cache[pindexPrev];
51
-
52
- // Now walk forward and compute the state of descendants of pindexPrev
53
- while (!vToCompute.empty()) {
54
- ThresholdState stateNext = state;
55
- pindexPrev = vToCompute.back();
56
- vToCompute.pop_back();
57
-
58
- switch (state) {
59
- case ThresholdState::DEFINED: {
60
- if (pindexPrev->GetMedianTimePast() >= nTimeStart) {
61
- stateNext = ThresholdState::STARTED;
62
- }
63
- break;
64
- }
65
- case ThresholdState::STARTED: {
66
- // We need to count
67
- const CBlockIndex* pindexCount = pindexPrev;
68
- int count = 0;
69
- for (int i = 0; i < nPeriod; i++) {
70
- if (Condition(pindexCount, params)) {
71
- count++;
72
- }
73
- pindexCount = pindexCount->pprev;
74
- }
75
- if (count >= nThreshold) {
76
- stateNext = ThresholdState::LOCKED_IN;
77
- } else if (pindexPrev->GetMedianTimePast() >= nTimeTimeout) {
78
- stateNext = ThresholdState::FAILED;
79
- }
80
- break;
81
- }
82
- case ThresholdState::LOCKED_IN: {
83
- // Progresses into ACTIVE provided activation height will have been reached.
84
- if (pindexPrev->nHeight + 1 >= min_activation_height) {
85
- stateNext = ThresholdState::ACTIVE;
86
- }
87
- break;
88
- }
89
- case ThresholdState::FAILED:
90
- case ThresholdState::ACTIVE: {
91
- // Nothing happens, these are terminal states.
92
- break;
93
- }
94
- }
95
- cache[pindexPrev] = state = stateNext;
96
- }
97
-
98
- return state;
99
- }
100
-
101
- BIP9Stats AbstractThresholdConditionChecker::GetStateStatisticsFor(const CBlockIndex* pindex, const Consensus::Params& params, std::vector<bool>* signalling_blocks) const
102
- {
103
- BIP9Stats stats = {};
104
-
105
- stats.period = Period(params);
106
- stats.threshold = Threshold(params);
107
-
108
- if (pindex == nullptr) return stats;
109
-
110
- // Find how many blocks are in the current period
111
- int blocks_in_period = 1 + (pindex->nHeight % stats.period);
112
-
113
- // Reset signalling_blocks
114
- if (signalling_blocks) {
115
- signalling_blocks->assign(blocks_in_period, false);
116
- }
117
-
118
- // Count from current block to beginning of period
119
- int elapsed = 0;
120
- int count = 0;
121
- const CBlockIndex* currentIndex = pindex;
122
- do {
123
- ++elapsed;
124
- --blocks_in_period;
125
- if (Condition(currentIndex, params)) {
126
- ++count;
127
- if (signalling_blocks) signalling_blocks->at(blocks_in_period) = true;
128
- }
129
- currentIndex = currentIndex->pprev;
130
- } while(blocks_in_period > 0);
131
-
132
- stats.elapsed = elapsed;
133
- stats.count = count;
134
- stats.possible = (stats.period - stats.threshold ) >= (stats.elapsed - count);
135
-
136
- return stats;
137
- }
138
-
139
- int AbstractThresholdConditionChecker::GetStateSinceHeightFor(const CBlockIndex* pindexPrev, const Consensus::Params& params, ThresholdConditionCache& cache) const
140
- {
141
- int64_t start_time = BeginTime(params);
142
- if (start_time == Consensus::BIP9Deployment::ALWAYS_ACTIVE || start_time == Consensus::BIP9Deployment::NEVER_ACTIVE) {
143
- return 0;
144
- }
145
-
146
- const ThresholdState initialState = GetStateFor(pindexPrev, params, cache);
147
-
148
- // BIP 9 about state DEFINED: "The genesis block is by definition in this state for each deployment."
149
- if (initialState == ThresholdState::DEFINED) {
150
- return 0;
151
- }
152
-
153
- const int nPeriod = Period(params);
154
-
155
- // A block's state is always the same as that of the first of its period, so it is computed based on a pindexPrev whose height equals a multiple of nPeriod - 1.
156
- // To ease understanding of the following height calculation, it helps to remember that
157
- // right now pindexPrev points to the block prior to the block that we are computing for, thus:
158
- // if we are computing for the last block of a period, then pindexPrev points to the second to last block of the period, and
159
- // if we are computing for the first block of a period, then pindexPrev points to the last block of the previous period.
160
- // The parent of the genesis block is represented by nullptr.
161
- pindexPrev = pindexPrev->GetAncestor(pindexPrev->nHeight - ((pindexPrev->nHeight + 1) % nPeriod));
162
-
163
- const CBlockIndex* previousPeriodParent = pindexPrev->GetAncestor(pindexPrev->nHeight - nPeriod);
164
-
165
- while (previousPeriodParent != nullptr && GetStateFor(previousPeriodParent, params, cache) == initialState) {
166
- pindexPrev = previousPeriodParent;
167
- previousPeriodParent = pindexPrev->GetAncestor(pindexPrev->nHeight - nPeriod);
168
- }
169
-
170
- // Adjust the result because right now we point to the parent block.
171
- return pindexPrev->nHeight + 1;
172
- }
173
-
174
- namespace
175
- {
176
- /**
177
- * Class to implement versionbits logic.
178
- */
179
- class VersionBitsConditionChecker : public AbstractThresholdConditionChecker {
180
- private:
181
- const Consensus::DeploymentPos id;
182
-
183
- protected:
184
- int64_t BeginTime(const Consensus::Params& params) const override { return params.vDeployments[id].nStartTime; }
185
- int64_t EndTime(const Consensus::Params& params) const override { return params.vDeployments[id].nTimeout; }
186
- int MinActivationHeight(const Consensus::Params& params) const override { return params.vDeployments[id].min_activation_height; }
187
- int Period(const Consensus::Params& params) const override { return params.nMinerConfirmationWindow; }
188
- int Threshold(const Consensus::Params& params) const override { return params.nRuleChangeActivationThreshold; }
189
-
190
- bool Condition(const CBlockIndex* pindex, const Consensus::Params& params) const override
191
- {
192
- return (((pindex->nVersion & VERSIONBITS_TOP_MASK) == VERSIONBITS_TOP_BITS) && (pindex->nVersion & Mask(params)) != 0);
193
- }
194
-
195
- public:
196
- explicit VersionBitsConditionChecker(Consensus::DeploymentPos id_) : id(id_) {}
197
- uint32_t Mask(const Consensus::Params& params) const { return ((uint32_t)1) << params.vDeployments[id].bit; }
198
- };
199
-
200
- } // namespace
201
-
202
- ThresholdState VersionBitsCache::State(const CBlockIndex* pindexPrev, const Consensus::Params& params, Consensus::DeploymentPos pos)
203
- {
204
- LOCK(m_mutex);
205
- return VersionBitsConditionChecker(pos).GetStateFor(pindexPrev, params, m_caches[pos]);
206
- }
207
-
208
- BIP9Stats VersionBitsCache::Statistics(const CBlockIndex* pindex, const Consensus::Params& params, Consensus::DeploymentPos pos, std::vector<bool>* signalling_blocks)
209
- {
210
- return VersionBitsConditionChecker(pos).GetStateStatisticsFor(pindex, params, signalling_blocks);
211
- }
212
-
213
- int VersionBitsCache::StateSinceHeight(const CBlockIndex* pindexPrev, const Consensus::Params& params, Consensus::DeploymentPos pos)
214
- {
215
- LOCK(m_mutex);
216
- return VersionBitsConditionChecker(pos).GetStateSinceHeightFor(pindexPrev, params, m_caches[pos]);
217
- }
218
-
219
- uint32_t VersionBitsCache::Mask(const Consensus::Params& params, Consensus::DeploymentPos pos)
220
- {
221
- return VersionBitsConditionChecker(pos).Mask(params);
222
- }
223
-
224
- int32_t VersionBitsCache::ComputeBlockVersion(const CBlockIndex* pindexPrev, const Consensus::Params& params)
225
- {
226
- LOCK(m_mutex);
227
- int32_t nVersion = VERSIONBITS_TOP_BITS;
228
-
229
- for (int i = 0; i < (int)Consensus::MAX_VERSION_BITS_DEPLOYMENTS; i++) {
230
- Consensus::DeploymentPos pos = static_cast<Consensus::DeploymentPos>(i);
231
- ThresholdState state = VersionBitsConditionChecker(pos).GetStateFor(pindexPrev, params, m_caches[pos]);
232
- if (state == ThresholdState::LOCKED_IN || state == ThresholdState::STARTED) {
233
- nVersion |= Mask(params, pos);
234
- }
235
- }
236
-
237
- return nVersion;
238
- }
239
-
240
- void VersionBitsCache::Clear()
241
- {
242
- LOCK(m_mutex);
243
- for (unsigned int d = 0; d < Consensus::MAX_VERSION_BITS_DEPLOYMENTS; d++) {
244
- m_caches[d].clear();
245
- }
246
- }
src/versionbits.h DELETED
@@ -1,107 +0,0 @@
1
- // Copyright (c) 2016-2021 The Bitcoin Core developers
2
- // Distributed under the MIT software license, see the accompanying
3
- // file COPYING or http://www.opensource.org/licenses/mit-license.php.
4
-
5
- #ifndef BITCOIN_VERSIONBITS_H
6
- #define BITCOIN_VERSIONBITS_H
7
-
8
- #include <chain.h>
9
- #include <sync.h>
10
-
11
- #include <map>
12
-
13
- /** What block version to use for new blocks (pre versionbits) */
14
- static const int32_t VERSIONBITS_LAST_OLD_BLOCK_VERSION = 4;
15
- /** What bits to set in version for versionbits blocks */
16
- static const int32_t VERSIONBITS_TOP_BITS = 0x20000000UL;
17
- /** What bitmask determines whether versionbits is in use */
18
- static const int32_t VERSIONBITS_TOP_MASK = 0xE0000000UL;
19
- /** Total bits available for versionbits */
20
- static const int32_t VERSIONBITS_NUM_BITS = 29;
21
-
22
- /** BIP 9 defines a finite-state-machine to deploy a softfork in multiple stages.
23
- * State transitions happen during retarget period if conditions are met
24
- * In case of reorg, transitions can go backward. Without transition, state is
25
- * inherited between periods. All blocks of a period share the same state.
26
- */
27
- enum class ThresholdState {
28
- DEFINED, // First state that each softfork starts out as. The genesis block is by definition in this state for each deployment.
29
- STARTED, // For blocks past the starttime.
30
- LOCKED_IN, // For at least one retarget period after the first retarget period with STARTED blocks of which at least threshold have the associated bit set in nVersion, until min_activation_height is reached.
31
- ACTIVE, // For all blocks after the LOCKED_IN retarget period (final state)
32
- FAILED, // For all blocks once the first retarget period after the timeout time is hit, if LOCKED_IN wasn't already reached (final state)
33
- };
34
-
35
- // A map that gives the state for blocks whose height is a multiple of Period().
36
- // The map is indexed by the block's parent, however, so all keys in the map
37
- // will either be nullptr or a block with (height + 1) % Period() == 0.
38
- typedef std::map<const CBlockIndex*, ThresholdState> ThresholdConditionCache;
39
-
40
- /** Display status of an in-progress BIP9 softfork */
41
- struct BIP9Stats {
42
- /** Length of blocks of the BIP9 signalling period */
43
- int period;
44
- /** Number of blocks with the version bit set required to activate the softfork */
45
- int threshold;
46
- /** Number of blocks elapsed since the beginning of the current period */
47
- int elapsed;
48
- /** Number of blocks with the version bit set since the beginning of the current period */
49
- int count;
50
- /** False if there are not enough blocks left in this period to pass activation threshold */
51
- bool possible;
52
- };
53
-
54
- /**
55
- * Abstract class that implements BIP9-style threshold logic, and caches results.
56
- */
57
- class AbstractThresholdConditionChecker {
58
- protected:
59
- virtual bool Condition(const CBlockIndex* pindex, const Consensus::Params& params) const =0;
60
- virtual int64_t BeginTime(const Consensus::Params& params) const =0;
61
- virtual int64_t EndTime(const Consensus::Params& params) const =0;
62
- virtual int MinActivationHeight(const Consensus::Params& params) const { return 0; }
63
- virtual int Period(const Consensus::Params& params) const =0;
64
- virtual int Threshold(const Consensus::Params& params) const =0;
65
-
66
- public:
67
- /** Returns the numerical statistics of an in-progress BIP9 softfork in the period including pindex
68
- * If provided, signalling_blocks is set to true/false based on whether each block in the period signalled
69
- */
70
- BIP9Stats GetStateStatisticsFor(const CBlockIndex* pindex, const Consensus::Params& params, std::vector<bool>* signalling_blocks = nullptr) const;
71
- /** Returns the state for pindex A based on parent pindexPrev B. Applies any state transition if conditions are present.
72
- * Caches state from first block of period. */
73
- ThresholdState GetStateFor(const CBlockIndex* pindexPrev, const Consensus::Params& params, ThresholdConditionCache& cache) const;
74
- /** Returns the height since when the ThresholdState has started for pindex A based on parent pindexPrev B, all blocks of a period share the same */
75
- int GetStateSinceHeightFor(const CBlockIndex* pindexPrev, const Consensus::Params& params, ThresholdConditionCache& cache) const;
76
- };
77
-
78
- /** BIP 9 allows multiple softforks to be deployed in parallel. We cache
79
- * per-period state for every one of them. */
80
- class VersionBitsCache
81
- {
82
- private:
83
- Mutex m_mutex;
84
- ThresholdConditionCache m_caches[Consensus::MAX_VERSION_BITS_DEPLOYMENTS] GUARDED_BY(m_mutex);
85
-
86
- public:
87
- /** Get the numerical statistics for a given deployment for the signalling period that includes pindex.
88
- * If provided, signalling_blocks is set to true/false based on whether each block in the period signalled
89
- */
90
- static BIP9Stats Statistics(const CBlockIndex* pindex, const Consensus::Params& params, Consensus::DeploymentPos pos, std::vector<bool>* signalling_blocks = nullptr);
91
-
92
- static uint32_t Mask(const Consensus::Params& params, Consensus::DeploymentPos pos);
93
-
94
- /** Get the BIP9 state for a given deployment for the block after pindexPrev. */
95
- ThresholdState State(const CBlockIndex* pindexPrev, const Consensus::Params& params, Consensus::DeploymentPos pos);
96
-
97
- /** Get the block height at which the BIP9 deployment switched into the state for the block after pindexPrev. */
98
- int StateSinceHeight(const CBlockIndex* pindexPrev, const Consensus::Params& params, Consensus::DeploymentPos pos);
99
-
100
- /** Determine what nVersion a new block should use
101
- */
102
- int32_t ComputeBlockVersion(const CBlockIndex* pindexPrev, const Consensus::Params& params);
103
-
104
- void Clear();
105
- };
106
-
107
- #endif // BITCOIN_VERSIONBITS_H
src/warnings.cpp CHANGED
@@ -15,6 +15,7 @@
15
15
  static Mutex g_warnings_mutex;
16
16
  static bilingual_str g_misc_warnings GUARDED_BY(g_warnings_mutex);
17
17
  static bool fLargeWorkInvalidChainFound GUARDED_BY(g_warnings_mutex) = false;
18
+ std::string strMintWarning;
18
19
 
19
20
  void SetMiscWarning(const bilingual_str& warning)
20
21
  {
@@ -41,6 +42,13 @@ bilingual_str GetWarnings(bool verbose)
41
42
  warnings_verbose.emplace_back(warnings_concise);
42
43
  }
43
44
 
45
+ // peercoin: wallet lock warning for minting
46
+ if (strMintWarning != "")
47
+ {
48
+ warnings_concise = Untranslated(strMintWarning);
49
+ warnings_verbose.emplace_back(warnings_concise);
50
+ }
51
+
44
52
  // Misc warnings like out of disk space and clock is wrong
45
53
  if (!g_misc_warnings.empty()) {
46
54
  warnings_concise = g_misc_warnings;
src/warnings.h CHANGED
@@ -20,4 +20,5 @@ void SetfLargeWorkInvalidChainFound(bool flag);
20
20
  */
21
21
  bilingual_str GetWarnings(bool verbose);
22
22
 
23
+ extern std::string strMintWarning;
23
24
  #endif // BITCOIN_WARNINGS_H